smart-spatial-system 0.2.7__tar.gz → 0.2.8__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 (437) hide show
  1. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/PKG-INFO +1 -1
  2. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/planning/llm_spec_generator.py +59 -0
  3. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/pyproject.toml +1 -1
  4. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system.egg-info/PKG-INFO +1 -1
  5. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system.egg-info/SOURCES.txt +1 -0
  6. smart_spatial_system-0.2.8/tests/test_spatial_join_ring_buffer_cardinality.py +215 -0
  7. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/LICENSE +0 -0
  8. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/README.md +0 -0
  9. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/api/__init__.py +0 -0
  10. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/api/auth.py +0 -0
  11. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/api/main.py +0 -0
  12. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/api/routers/__init__.py +0 -0
  13. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/api/routers/data_source_connectors.py +0 -0
  14. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/api/routers/data_sources.py +0 -0
  15. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/api/routers/plugins_settings.py +0 -0
  16. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/api/routers/projects.py +0 -0
  17. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/api/routers/query_planner.py +0 -0
  18. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/api/routers/requests_outputs.py +0 -0
  19. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/api/routers/system.py +0 -0
  20. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/api/routers/uploads.py +0 -0
  21. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/api/routers/weights.py +0 -0
  22. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/api/support.py +0 -0
  23. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/__init__.py +0 -0
  24. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/__init__.py +0 -0
  25. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/area_perimeter_calc.example.yaml +0 -0
  26. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/area_perimeter_calc.yaml +0 -0
  27. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/attribute_statistics.example.yaml +0 -0
  28. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/attribute_statistics.yaml +0 -0
  29. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/band_math.example.yaml +0 -0
  30. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/band_math.yaml +0 -0
  31. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/buffer_analysis.example.yaml +0 -0
  32. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/buffer_analysis.yaml +0 -0
  33. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/centroid_extractor.example.yaml +0 -0
  34. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/centroid_extractor.yaml +0 -0
  35. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/core_vector.example.yaml +0 -0
  36. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/core_vector.yaml +0 -0
  37. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/crs_transformer.example.yaml +0 -0
  38. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/crs_transformer.yaml +0 -0
  39. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/data_writer_exporter.example.yaml +0 -0
  40. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/data_writer_exporter.yaml +0 -0
  41. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/dissolve_aggregator.example.yaml +0 -0
  42. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/dissolve_aggregator.yaml +0 -0
  43. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/distance_calculator.example.yaml +0 -0
  44. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/distance_calculator.yaml +0 -0
  45. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/feature_enrichment.example.yaml +0 -0
  46. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/feature_enrichment.yaml +0 -0
  47. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/feature_scoring.example.yaml +0 -0
  48. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/feature_scoring.yaml +0 -0
  49. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/geocoding_resolver.example.yaml +0 -0
  50. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/geocoding_resolver.yaml +0 -0
  51. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/geometry_validator.example.yaml +0 -0
  52. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/geometry_validator.yaml +0 -0
  53. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/local_raster_loader.example.yaml +0 -0
  54. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/local_raster_loader.yaml +0 -0
  55. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/local_vector_loader.example.yaml +0 -0
  56. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/local_vector_loader.yaml +0 -0
  57. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/ndvi_calculator.example.yaml +0 -0
  58. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/ndvi_calculator.yaml +0 -0
  59. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/nearest_neighbor.example.yaml +0 -0
  60. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/nearest_neighbor.yaml +0 -0
  61. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/postgis_connector.example.yaml +0 -0
  62. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/postgis_connector.yaml +0 -0
  63. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/raster_clip_mask.example.yaml +0 -0
  64. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/raster_clip_mask.yaml +0 -0
  65. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/raster_reclassify.example.yaml +0 -0
  66. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/raster_reclassify.yaml +0 -0
  67. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/raster_statistics.example.yaml +0 -0
  68. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/raster_statistics.yaml +0 -0
  69. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/raster_threshold.example.yaml +0 -0
  70. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/raster_threshold.yaml +0 -0
  71. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/raster_to_vector.example.yaml +0 -0
  72. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/raster_to_vector.yaml +0 -0
  73. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/ring_buffer_analysis.example.yaml +0 -0
  74. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/ring_buffer_analysis.yaml +0 -0
  75. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/risk_enrichment.example.yaml +0 -0
  76. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/risk_enrichment.yaml +0 -0
  77. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/slope_aspect.yaml +0 -0
  78. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/spatial_intersection.example.yaml +0 -0
  79. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/spatial_intersection.yaml +0 -0
  80. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/spatial_join.example.yaml +0 -0
  81. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/spatial_join.yaml +0 -0
  82. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/spatial_predicate.example.yaml +0 -0
  83. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/spatial_predicate.yaml +0 -0
  84. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/spatial_query_filter.example.yaml +0 -0
  85. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/spatial_query_filter.yaml +0 -0
  86. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/spectral_indices.example.yaml +0 -0
  87. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/spectral_indices.yaml +0 -0
  88. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/wms_wfs_fetcher.example.yaml +0 -0
  89. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/wms_wfs_fetcher.yaml +0 -0
  90. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/zonal_statistics.example.yaml +0 -0
  91. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/config/plugins/zonal_statistics.yaml +0 -0
  92. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/__init__.py +0 -0
  93. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/audit.py +0 -0
  94. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/capability_registry.py +0 -0
  95. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/capability_router.py +0 -0
  96. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/capability_scoring.py +0 -0
  97. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/data_source_service.py +0 -0
  98. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/error_contract.py +0 -0
  99. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/feedback.py +0 -0
  100. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/feedback_proposal_service.py +0 -0
  101. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/input_error_mapping.py +0 -0
  102. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/input_reference_resolver.py +0 -0
  103. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/kernel_artifacts.py +0 -0
  104. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/learning_signals.py +0 -0
  105. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/llm_client.py +0 -0
  106. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/llm_gate.py +0 -0
  107. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/llm_intent_planner.py +0 -0
  108. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/loader_plugin_contract.py +0 -0
  109. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/map_layer_service.py +0 -0
  110. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/map_layers.py +0 -0
  111. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/models.py +0 -0
  112. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/natural_query_runner.py +0 -0
  113. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/output_service.py +0 -0
  114. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/output_storage.py +0 -0
  115. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/pipeline_executor.py +0 -0
  116. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/plan_builder.py +0 -0
  117. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/planning/__init__.py +0 -0
  118. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/planning/capability_resolver.py +0 -0
  119. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/planning/dag.py +0 -0
  120. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/planning/dag_executor.py +0 -0
  121. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/planning/error_mapping.py +0 -0
  122. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/planning/kernel_execution_bridge.py +0 -0
  123. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/planning/kernel_plan_adapter.py +0 -0
  124. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/planning/llm_query_spec.py +0 -0
  125. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/planning/op_catalog.py +0 -0
  126. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/planning/output_parity.py +0 -0
  127. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/planning/planner.py +0 -0
  128. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/planning/postgis_semantic_resolver.py +0 -0
  129. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/planning/query_spec_contract.py +0 -0
  130. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/planning/report_spec.py +0 -0
  131. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/planning/runner.py +0 -0
  132. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/planning/semantic_planning_context.py +0 -0
  133. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/planning/spec.py +0 -0
  134. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/plugin_config_store.py +0 -0
  135. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/plugin_error_mapping.py +0 -0
  136. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/plugin_modules.py +0 -0
  137. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/plugin_runtime_service.py +0 -0
  138. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/plugin_state.py +0 -0
  139. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/production_response.py +0 -0
  140. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/project_service.py +0 -0
  141. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/project_store.py +0 -0
  142. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/provider_error_mapping.py +0 -0
  143. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/query_execution_service.py +0 -0
  144. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/query_parser.py +0 -0
  145. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/request_history_service.py +0 -0
  146. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/response_assembler.py +0 -0
  147. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/response_builder.py +0 -0
  148. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/router_decision.py +0 -0
  149. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/routing_aware_natural_query_runner.py +0 -0
  150. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/routing_aware_plan_builder.py +0 -0
  151. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/runtime_paths.py +0 -0
  152. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/service.py +0 -0
  153. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/statistics.py +0 -0
  154. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/upload_service.py +0 -0
  155. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/upload_storage.py +0 -0
  156. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/weight_proposals.py +0 -0
  157. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/weight_store_persistence.py +0 -0
  158. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/orchestrator/weighted_router.py +0 -0
  159. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/__init__.py +0 -0
  160. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/_shared/__init__.py +0 -0
  161. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/_shared/local_path_validation.py +0 -0
  162. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/_shared/numeric_validation.py +0 -0
  163. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/_shared/plugin_config.py +0 -0
  164. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/area_perimeter_calc.py +0 -0
  165. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/attribute_statistics.py +0 -0
  166. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/band_math.py +0 -0
  167. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/buffer_analysis.py +0 -0
  168. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/centroid_extractor.py +0 -0
  169. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/core_vector.py +0 -0
  170. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/crs_transformer.py +0 -0
  171. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/data_writer_exporter.py +0 -0
  172. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/dissolve_aggregator.py +0 -0
  173. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/distance_calculator.py +0 -0
  174. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/feature_enrichment.py +0 -0
  175. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/feature_scoring.py +0 -0
  176. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/geocoding_resolver.py +0 -0
  177. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/geometry_validator.py +0 -0
  178. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/local_raster_loader.py +0 -0
  179. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/local_vector_loader.py +0 -0
  180. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/ndvi_analysis.py +0 -0
  181. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/ndvi_calculator.py +0 -0
  182. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/nearest_neighbor.py +0 -0
  183. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/pdf_renderer.py +0 -0
  184. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/postgis_connector.py +0 -0
  185. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/raster_clip_mask.py +0 -0
  186. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/raster_reclassify.py +0 -0
  187. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/raster_statistics.py +0 -0
  188. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/raster_threshold.py +0 -0
  189. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/raster_to_vector.py +0 -0
  190. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/real_estate_scoring.py +0 -0
  191. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/real_estate_spatial_enrichment.py +0 -0
  192. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/report_builder.py +0 -0
  193. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/ring_buffer_analysis.py +0 -0
  194. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/risk_enrichment.py +0 -0
  195. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/slope_aspect.py +0 -0
  196. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/spatial_intersection.py +0 -0
  197. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/spatial_join.py +0 -0
  198. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/spatial_predicate.py +0 -0
  199. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/spatial_query_filter.py +0 -0
  200. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/spectral_indices.py +0 -0
  201. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/wms_wfs_fetcher.py +0 -0
  202. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/plugins/zonal_statistics.py +0 -0
  203. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/setup.cfg +0 -0
  204. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/__init__.py +0 -0
  205. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/__main__.py +0 -0
  206. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/__init__.py +0 -0
  207. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/__init__.py +0 -0
  208. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/data_source_service.py +0 -0
  209. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/feedback_proposal_service.py +0 -0
  210. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/llm_intent_adapter.py +0 -0
  211. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/map_layer_service.py +0 -0
  212. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/output_service.py +0 -0
  213. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/planning_execution_policy.py +0 -0
  214. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/planning_response_adapter.py +0 -0
  215. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/plugin_runtime_service.py +0 -0
  216. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/project_service.py +0 -0
  217. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/__init__.py +0 -0
  218. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/accessibility_query_spec.py +0 -0
  219. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/direct_query_dispatch.py +0 -0
  220. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/natural_query_context.py +0 -0
  221. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/natural_query_dispatch.py +0 -0
  222. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/natural_query_execution.py +0 -0
  223. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/natural_query_failure.py +0 -0
  224. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/natural_query_persistence.py +0 -0
  225. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/planning_context.py +0 -0
  226. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/planning_execution.py +0 -0
  227. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/planning_persistence.py +0 -0
  228. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/planning_response.py +0 -0
  229. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/postgis_planning_context.py +0 -0
  230. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/real_estate_analysis_inspector.py +0 -0
  231. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/real_estate_classifier.py +0 -0
  232. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/real_estate_context.py +0 -0
  233. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/real_estate_document_renderer.py +0 -0
  234. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/real_estate_missing_inputs.py +0 -0
  235. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/real_estate_ranking_artifacts.py +0 -0
  236. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/real_estate_ranking_direct_handler.py +0 -0
  237. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/real_estate_ranking_execution.py +0 -0
  238. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/real_estate_ranking_query_spec.py +0 -0
  239. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/real_estate_ranking_response.py +0 -0
  240. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/real_estate_report_payload.py +0 -0
  241. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution/real_estate_scoring.py +0 -0
  242. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_execution_service.py +0 -0
  243. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/query_spec_enrichment.py +0 -0
  244. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/real_estate_spatial_helpers.py +0 -0
  245. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/request_history_service.py +0 -0
  246. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/system_status_query_handler.py +0 -0
  247. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/upload_service.py +0 -0
  248. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/vector_display_handler.py +0 -0
  249. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/vector_geojson_helpers.py +0 -0
  250. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/application/services/vector_query_classifier.py +0 -0
  251. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/cli.py +0 -0
  252. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/domain/__init__.py +0 -0
  253. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/domain/contracts/__init__.py +0 -0
  254. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/domain/models/__init__.py +0 -0
  255. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/infrastructure/__init__.py +0 -0
  256. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/infrastructure/stores/__init__.py +0 -0
  257. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/interfaces/__init__.py +0 -0
  258. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/interfaces/api/__init__.py +0 -0
  259. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/interfaces/api/routers/__init__.py +0 -0
  260. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/plugins/__init__.py +0 -0
  261. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/runtime/__init__.py +0 -0
  262. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/shared/__init__.py +0 -0
  263. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/workflows/__init__.py +0 -0
  264. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/workflows/ndvi/__init__.py +0 -0
  265. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system/workflows/real_estate/__init__.py +0 -0
  266. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system.egg-info/dependency_links.txt +0 -0
  267. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system.egg-info/entry_points.txt +0 -0
  268. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system.egg-info/requires.txt +0 -0
  269. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/smart_spatial_system.egg-info/top_level.txt +0 -0
  270. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/templates/__init__.py +0 -0
  271. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/templates/reports/__init__.py +0 -0
  272. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/templates/reports/real_estate_report.html +0 -0
  273. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_accessibility_query_spec.py +0 -0
  274. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_api_auth.py +0 -0
  275. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_api_contract_smoke.py +0 -0
  276. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_api_data_source_connectors_e2e.py +0 -0
  277. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_api_map_layers.py +0 -0
  278. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_api_mvp.py +0 -0
  279. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_api_outputs.py +0 -0
  280. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_api_projects.py +0 -0
  281. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_api_structured_error_normalization.py +0 -0
  282. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_api_upload_plugin_resolver.py +0 -0
  283. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_api_uploads.py +0 -0
  284. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_area_perimeter_calc.py +0 -0
  285. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_attribute_statistics.py +0 -0
  286. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_band_math.py +0 -0
  287. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_buffer_analysis.py +0 -0
  288. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_centroid_extractor.py +0 -0
  289. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_cli.py +0 -0
  290. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_crs_transformer.py +0 -0
  291. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_data_source_service.py +0 -0
  292. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_data_writer_exporter.py +0 -0
  293. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_deterministic_planner.py +0 -0
  294. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_dissolve_aggregator.py +0 -0
  295. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_distance_calculator.py +0 -0
  296. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_document_file_report_contract.py +0 -0
  297. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_end_to_end_natural_query_pipeline.py +0 -0
  298. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_error_contract.py +0 -0
  299. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_feature_enrichment.py +0 -0
  300. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_feature_scoring.py +0 -0
  301. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_frontend_api_surface_contract.py +0 -0
  302. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_geocoding_resolver.py +0 -0
  303. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_geocoding_resolver_error_redaction.py +0 -0
  304. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_geometry_validator.py +0 -0
  305. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_input_error_mapping.py +0 -0
  306. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_input_reference_resolver.py +0 -0
  307. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_input_reference_resolver_contract.py +0 -0
  308. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_kernel_artifacts.py +0 -0
  309. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_kernel_execution_bridge.py +0 -0
  310. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_kernel_plan_adapter.py +0 -0
  311. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_llm_intent_adapter.py +0 -0
  312. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_llm_raster_queryspec_normalization.py +0 -0
  313. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_llm_spec_generator.py +0 -0
  314. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_llm_spec_generator_prenormalize.py +0 -0
  315. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_llm_spec_generator_semantic_context.py +0 -0
  316. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_llm_spec_generator_semantic_query_database_enrich.py +0 -0
  317. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_llm_spec_generator_semantic_queryspec_repair.py +0 -0
  318. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_loader_plugin_contract.py +0 -0
  319. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_local_path_validation.py +0 -0
  320. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_local_raster_loader.py +0 -0
  321. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_local_raster_loader_contract.py +0 -0
  322. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_local_vector_loader.py +0 -0
  323. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_local_vector_loader_contract.py +0 -0
  324. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_map_layer_contract.py +0 -0
  325. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_map_layer_service.py +0 -0
  326. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_ndvi_calculator.py +0 -0
  327. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_nearest_neighbor.py +0 -0
  328. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_numeric_validation.py +0 -0
  329. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_op_catalog_semantic_aliases.py +0 -0
  330. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_audit.py +0 -0
  331. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_audit_integration.py +0 -0
  332. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_data_source_service_integration.py +0 -0
  333. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_feedback.py +0 -0
  334. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_feedback_integration.py +0 -0
  335. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_keyword_scoring_router.py +0 -0
  336. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_learning_signals.py +0 -0
  337. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_learning_signals_integration.py +0 -0
  338. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_llm_gate.py +0 -0
  339. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_llm_gate_integration.py +0 -0
  340. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_map_layer_service_integration.py +0 -0
  341. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_natural_query_pipeline.py +0 -0
  342. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_output_service_integration.py +0 -0
  343. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_production_response.py +0 -0
  344. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_production_response_integration.py +0 -0
  345. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_project_service_integration.py +0 -0
  346. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_query_execution_service_integration.py +0 -0
  347. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_registry_router.py +0 -0
  348. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_router_decision.py +0 -0
  349. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_router_decision_integration.py +0 -0
  350. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_routing_aware_plan_builder.py +0 -0
  351. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_runtime_paths.py +0 -0
  352. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_service.py +0 -0
  353. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_service_domain_boundary_contract.py +0 -0
  354. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_service_integration.py +0 -0
  355. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_service_postgis_dedup_contract.py +0 -0
  356. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_statistics.py +0 -0
  357. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_statistics_integration.py +0 -0
  358. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_upload_service_integration.py +0 -0
  359. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_weight_proposals.py +0 -0
  360. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_weight_proposals_integration.py +0 -0
  361. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_weight_store_persistence.py +0 -0
  362. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_weight_store_persistence_integration.py +0 -0
  363. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_weighted_router.py +0 -0
  364. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_orchestrator_weighted_router_integration.py +0 -0
  365. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_output_service.py +0 -0
  366. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_output_storage.py +0 -0
  367. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_pdf_renderer.py +0 -0
  368. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_phase3_kernel_registry_coverage.py +0 -0
  369. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_phase3_output_parity.py +0 -0
  370. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_phase3_postgis_provider_kernel_execution.py +0 -0
  371. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_planning_dag_executor.py +0 -0
  372. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_planning_dag_executor_async_capability.py +0 -0
  373. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_planning_error_mapping.py +0 -0
  374. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_planning_execution_policy.py +0 -0
  375. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_planning_raster_op_catalog_mapping.py +0 -0
  376. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_planning_raster_queryspec_execution.py +0 -0
  377. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_planning_registry_backed_raster_execution.py +0 -0
  378. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_planning_registry_backed_real_estate_execution.py +0 -0
  379. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_planning_runner.py +0 -0
  380. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_plugin_boundary_contract.py +0 -0
  381. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_plugin_config.py +0 -0
  382. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_plugin_config_store.py +0 -0
  383. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_plugin_error_mapping.py +0 -0
  384. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_plugin_modules.py +0 -0
  385. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_postgis_connector.py +0 -0
  386. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_postgis_connector_percent_escape.py +0 -0
  387. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_postgis_semantic_resolver.py +0 -0
  388. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_project_service.py +0 -0
  389. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_project_store.py +0 -0
  390. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_provider_error_mapping.py +0 -0
  391. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_query_dispatch_domain_boundary_contract.py +0 -0
  392. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_query_execution_postgis_planning_context.py +0 -0
  393. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_query_execution_service.py +0 -0
  394. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_query_execution_service_domain_import_boundary_contract.py +0 -0
  395. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_query_response_shape_golden.py +0 -0
  396. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_query_spec_enrichment.py +0 -0
  397. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_raster_capability_registry_contract.py +0 -0
  398. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_raster_clip_mask.py +0 -0
  399. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_raster_reclassify.py +0 -0
  400. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_raster_statistics.py +0 -0
  401. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_raster_threshold.py +0 -0
  402. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_raster_to_vector.py +0 -0
  403. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_real_estate_ranking_bridge.py +0 -0
  404. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_real_estate_ranking_golden.py +0 -0
  405. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_real_estate_ranking_query_spec_planning.py +0 -0
  406. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_real_estate_scoring_plugin.py +0 -0
  407. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_real_estate_spatial_enrichment_plugin.py +0 -0
  408. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_real_estate_spatial_helpers.py +0 -0
  409. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_report_builder.py +0 -0
  410. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_report_spec.py +0 -0
  411. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_request_document_download_contract.py +0 -0
  412. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_response_assembler.py +0 -0
  413. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_response_output_contract.py +0 -0
  414. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_ring_buffer_analysis.py +0 -0
  415. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_risk_enrichment.py +0 -0
  416. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_runtime_paths.py +0 -0
  417. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_semantic_planning_context.py +0 -0
  418. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_service_auto_postgis_semantic_context.py +0 -0
  419. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_service_planning_artifacts.py +0 -0
  420. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_service_postgis_runtime_connection_injection.py +0 -0
  421. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_service_semantic_planning_context.py +0 -0
  422. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_service_strict_loader_contract.py +0 -0
  423. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_service_structured_error_normalization.py +0 -0
  424. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_slope_aspect.py +0 -0
  425. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_spatial_intersection.py +0 -0
  426. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_spatial_join.py +0 -0
  427. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_spatial_query_filter.py +0 -0
  428. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_spectral_indices.py +0 -0
  429. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_system_status_query_handler.py +0 -0
  430. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_upload_service.py +0 -0
  431. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_upload_storage.py +0 -0
  432. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_vector_display_handler.py +0 -0
  433. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_vector_geojson_helpers.py +0 -0
  434. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_vector_query_classifier.py +0 -0
  435. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_wms_wfs_fetcher.py +0 -0
  436. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/tests/test_wms_wfs_fetcher_error_redaction.py +0 -0
  437. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.8}/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.8
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,
@@ -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.8"
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.8
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,7 @@ 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
424
425
  tests/test_spatial_query_filter.py
425
426
  tests/test_spectral_indices.py
426
427
  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"