smart-spatial-system 0.2.2__tar.gz → 0.2.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (432) hide show
  1. {smart_spatial_system-0.2.2/smart_spatial_system.egg-info → smart_spatial_system-0.2.4}/PKG-INFO +1 -1
  2. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/distance_calculator.example.yaml +1 -0
  3. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/distance_calculator.yaml +1 -0
  4. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/nearest_neighbor.example.yaml +1 -0
  5. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/nearest_neighbor.yaml +1 -0
  6. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/planning/llm_spec_generator.py +228 -7
  7. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/planning/op_catalog.py +8 -0
  8. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/distance_calculator.py +68 -1
  9. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/feature_scoring.py +23 -1
  10. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/nearest_neighbor.py +25 -1
  11. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/pyproject.toml +1 -1
  12. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/accessibility_query_spec.py +11 -1
  13. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4/smart_spatial_system.egg-info}/PKG-INFO +1 -1
  14. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_distance_calculator.py +60 -0
  15. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_feature_scoring.py +44 -0
  16. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_llm_spec_generator.py +313 -0
  17. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_nearest_neighbor.py +44 -0
  18. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_op_catalog_semantic_aliases.py +13 -0
  19. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/LICENSE +0 -0
  20. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/README.md +0 -0
  21. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/api/__init__.py +0 -0
  22. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/api/auth.py +0 -0
  23. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/api/main.py +0 -0
  24. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/api/routers/__init__.py +0 -0
  25. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/api/routers/data_source_connectors.py +0 -0
  26. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/api/routers/data_sources.py +0 -0
  27. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/api/routers/plugins_settings.py +0 -0
  28. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/api/routers/projects.py +0 -0
  29. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/api/routers/query_planner.py +0 -0
  30. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/api/routers/requests_outputs.py +0 -0
  31. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/api/routers/system.py +0 -0
  32. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/api/routers/uploads.py +0 -0
  33. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/api/routers/weights.py +0 -0
  34. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/api/support.py +0 -0
  35. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/__init__.py +0 -0
  36. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/__init__.py +0 -0
  37. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/area_perimeter_calc.example.yaml +0 -0
  38. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/area_perimeter_calc.yaml +0 -0
  39. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/attribute_statistics.example.yaml +0 -0
  40. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/attribute_statistics.yaml +0 -0
  41. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/band_math.example.yaml +0 -0
  42. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/band_math.yaml +0 -0
  43. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/buffer_analysis.example.yaml +0 -0
  44. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/buffer_analysis.yaml +0 -0
  45. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/centroid_extractor.example.yaml +0 -0
  46. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/centroid_extractor.yaml +0 -0
  47. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/core_vector.example.yaml +0 -0
  48. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/core_vector.yaml +0 -0
  49. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/crs_transformer.example.yaml +0 -0
  50. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/crs_transformer.yaml +0 -0
  51. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/data_writer_exporter.example.yaml +0 -0
  52. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/data_writer_exporter.yaml +0 -0
  53. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/dissolve_aggregator.example.yaml +0 -0
  54. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/dissolve_aggregator.yaml +0 -0
  55. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/feature_enrichment.example.yaml +0 -0
  56. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/feature_enrichment.yaml +0 -0
  57. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/feature_scoring.example.yaml +0 -0
  58. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/feature_scoring.yaml +0 -0
  59. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/geocoding_resolver.example.yaml +0 -0
  60. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/geocoding_resolver.yaml +0 -0
  61. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/geometry_validator.example.yaml +0 -0
  62. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/geometry_validator.yaml +0 -0
  63. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/local_raster_loader.example.yaml +0 -0
  64. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/local_raster_loader.yaml +0 -0
  65. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/local_vector_loader.example.yaml +0 -0
  66. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/local_vector_loader.yaml +0 -0
  67. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/ndvi_calculator.example.yaml +0 -0
  68. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/ndvi_calculator.yaml +0 -0
  69. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/postgis_connector.example.yaml +0 -0
  70. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/postgis_connector.yaml +0 -0
  71. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/raster_clip_mask.example.yaml +0 -0
  72. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/raster_clip_mask.yaml +0 -0
  73. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/raster_reclassify.example.yaml +0 -0
  74. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/raster_reclassify.yaml +0 -0
  75. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/raster_statistics.example.yaml +0 -0
  76. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/raster_statistics.yaml +0 -0
  77. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/raster_threshold.example.yaml +0 -0
  78. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/raster_threshold.yaml +0 -0
  79. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/raster_to_vector.example.yaml +0 -0
  80. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/raster_to_vector.yaml +0 -0
  81. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/risk_enrichment.example.yaml +0 -0
  82. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/risk_enrichment.yaml +0 -0
  83. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/slope_aspect.yaml +0 -0
  84. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/spatial_intersection.example.yaml +0 -0
  85. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/spatial_intersection.yaml +0 -0
  86. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/spatial_join.example.yaml +0 -0
  87. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/spatial_join.yaml +0 -0
  88. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/spatial_predicate.example.yaml +0 -0
  89. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/spatial_predicate.yaml +0 -0
  90. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/spatial_query_filter.example.yaml +0 -0
  91. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/spatial_query_filter.yaml +0 -0
  92. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/spectral_indices.example.yaml +0 -0
  93. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/spectral_indices.yaml +0 -0
  94. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/wms_wfs_fetcher.example.yaml +0 -0
  95. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/wms_wfs_fetcher.yaml +0 -0
  96. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/zonal_statistics.example.yaml +0 -0
  97. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/config/plugins/zonal_statistics.yaml +0 -0
  98. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/__init__.py +0 -0
  99. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/audit.py +0 -0
  100. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/capability_registry.py +0 -0
  101. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/capability_router.py +0 -0
  102. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/capability_scoring.py +0 -0
  103. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/data_source_service.py +0 -0
  104. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/error_contract.py +0 -0
  105. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/feedback.py +0 -0
  106. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/feedback_proposal_service.py +0 -0
  107. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/input_error_mapping.py +0 -0
  108. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/input_reference_resolver.py +0 -0
  109. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/kernel_artifacts.py +0 -0
  110. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/learning_signals.py +0 -0
  111. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/llm_client.py +0 -0
  112. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/llm_gate.py +0 -0
  113. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/llm_intent_planner.py +0 -0
  114. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/loader_plugin_contract.py +0 -0
  115. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/map_layer_service.py +0 -0
  116. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/map_layers.py +0 -0
  117. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/models.py +0 -0
  118. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/natural_query_runner.py +0 -0
  119. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/output_service.py +0 -0
  120. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/output_storage.py +0 -0
  121. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/pipeline_executor.py +0 -0
  122. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/plan_builder.py +0 -0
  123. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/planning/__init__.py +0 -0
  124. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/planning/capability_resolver.py +0 -0
  125. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/planning/dag.py +0 -0
  126. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/planning/dag_executor.py +0 -0
  127. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/planning/error_mapping.py +0 -0
  128. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/planning/kernel_execution_bridge.py +0 -0
  129. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/planning/kernel_plan_adapter.py +0 -0
  130. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/planning/llm_query_spec.py +0 -0
  131. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/planning/output_parity.py +0 -0
  132. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/planning/planner.py +0 -0
  133. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/planning/postgis_semantic_resolver.py +0 -0
  134. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/planning/query_spec_contract.py +0 -0
  135. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/planning/report_spec.py +0 -0
  136. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/planning/runner.py +0 -0
  137. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/planning/semantic_planning_context.py +0 -0
  138. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/planning/spec.py +0 -0
  139. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/plugin_config_store.py +0 -0
  140. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/plugin_error_mapping.py +0 -0
  141. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/plugin_modules.py +0 -0
  142. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/plugin_runtime_service.py +0 -0
  143. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/plugin_state.py +0 -0
  144. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/production_response.py +0 -0
  145. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/project_service.py +0 -0
  146. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/project_store.py +0 -0
  147. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/provider_error_mapping.py +0 -0
  148. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/query_execution_service.py +0 -0
  149. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/query_parser.py +0 -0
  150. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/request_history_service.py +0 -0
  151. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/response_assembler.py +0 -0
  152. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/response_builder.py +0 -0
  153. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/router_decision.py +0 -0
  154. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/routing_aware_natural_query_runner.py +0 -0
  155. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/routing_aware_plan_builder.py +0 -0
  156. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/runtime_paths.py +0 -0
  157. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/service.py +0 -0
  158. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/statistics.py +0 -0
  159. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/upload_service.py +0 -0
  160. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/upload_storage.py +0 -0
  161. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/weight_proposals.py +0 -0
  162. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/weight_store_persistence.py +0 -0
  163. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/orchestrator/weighted_router.py +0 -0
  164. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/__init__.py +0 -0
  165. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/_shared/__init__.py +0 -0
  166. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/_shared/local_path_validation.py +0 -0
  167. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/_shared/numeric_validation.py +0 -0
  168. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/_shared/plugin_config.py +0 -0
  169. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/area_perimeter_calc.py +0 -0
  170. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/attribute_statistics.py +0 -0
  171. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/band_math.py +0 -0
  172. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/buffer_analysis.py +0 -0
  173. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/centroid_extractor.py +0 -0
  174. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/core_vector.py +0 -0
  175. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/crs_transformer.py +0 -0
  176. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/data_writer_exporter.py +0 -0
  177. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/dissolve_aggregator.py +0 -0
  178. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/feature_enrichment.py +0 -0
  179. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/geocoding_resolver.py +0 -0
  180. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/geometry_validator.py +0 -0
  181. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/local_raster_loader.py +0 -0
  182. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/local_vector_loader.py +0 -0
  183. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/ndvi_analysis.py +0 -0
  184. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/ndvi_calculator.py +0 -0
  185. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/pdf_renderer.py +0 -0
  186. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/postgis_connector.py +0 -0
  187. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/raster_clip_mask.py +0 -0
  188. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/raster_reclassify.py +0 -0
  189. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/raster_statistics.py +0 -0
  190. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/raster_threshold.py +0 -0
  191. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/raster_to_vector.py +0 -0
  192. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/real_estate_scoring.py +0 -0
  193. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/real_estate_spatial_enrichment.py +0 -0
  194. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/report_builder.py +0 -0
  195. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/risk_enrichment.py +0 -0
  196. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/slope_aspect.py +0 -0
  197. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/spatial_intersection.py +0 -0
  198. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/spatial_join.py +0 -0
  199. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/spatial_predicate.py +0 -0
  200. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/spatial_query_filter.py +0 -0
  201. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/spectral_indices.py +0 -0
  202. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/wms_wfs_fetcher.py +0 -0
  203. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/plugins/zonal_statistics.py +0 -0
  204. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/setup.cfg +0 -0
  205. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/__init__.py +0 -0
  206. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/__main__.py +0 -0
  207. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/__init__.py +0 -0
  208. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/__init__.py +0 -0
  209. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/data_source_service.py +0 -0
  210. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/feedback_proposal_service.py +0 -0
  211. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/llm_intent_adapter.py +0 -0
  212. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/map_layer_service.py +0 -0
  213. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/output_service.py +0 -0
  214. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/planning_execution_policy.py +0 -0
  215. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/planning_response_adapter.py +0 -0
  216. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/plugin_runtime_service.py +0 -0
  217. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/project_service.py +0 -0
  218. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/__init__.py +0 -0
  219. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/direct_query_dispatch.py +0 -0
  220. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/natural_query_context.py +0 -0
  221. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/natural_query_dispatch.py +0 -0
  222. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/natural_query_execution.py +0 -0
  223. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/natural_query_failure.py +0 -0
  224. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/natural_query_persistence.py +0 -0
  225. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/planning_context.py +0 -0
  226. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/planning_execution.py +0 -0
  227. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/planning_persistence.py +0 -0
  228. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/planning_response.py +0 -0
  229. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/postgis_planning_context.py +0 -0
  230. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/real_estate_analysis_inspector.py +0 -0
  231. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/real_estate_classifier.py +0 -0
  232. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/real_estate_context.py +0 -0
  233. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/real_estate_document_renderer.py +0 -0
  234. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/real_estate_missing_inputs.py +0 -0
  235. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/real_estate_ranking_artifacts.py +0 -0
  236. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/real_estate_ranking_direct_handler.py +0 -0
  237. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/real_estate_ranking_execution.py +0 -0
  238. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/real_estate_ranking_query_spec.py +0 -0
  239. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/real_estate_ranking_response.py +0 -0
  240. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/real_estate_report_payload.py +0 -0
  241. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution/real_estate_scoring.py +0 -0
  242. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_execution_service.py +0 -0
  243. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/query_spec_enrichment.py +0 -0
  244. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/real_estate_spatial_helpers.py +0 -0
  245. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/request_history_service.py +0 -0
  246. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/system_status_query_handler.py +0 -0
  247. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/upload_service.py +0 -0
  248. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/vector_display_handler.py +0 -0
  249. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/vector_geojson_helpers.py +0 -0
  250. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/application/services/vector_query_classifier.py +0 -0
  251. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/cli.py +0 -0
  252. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/domain/__init__.py +0 -0
  253. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/domain/contracts/__init__.py +0 -0
  254. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/domain/models/__init__.py +0 -0
  255. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/infrastructure/__init__.py +0 -0
  256. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/infrastructure/stores/__init__.py +0 -0
  257. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/interfaces/__init__.py +0 -0
  258. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/interfaces/api/__init__.py +0 -0
  259. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/interfaces/api/routers/__init__.py +0 -0
  260. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/plugins/__init__.py +0 -0
  261. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/runtime/__init__.py +0 -0
  262. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/shared/__init__.py +0 -0
  263. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/workflows/__init__.py +0 -0
  264. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/workflows/ndvi/__init__.py +0 -0
  265. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system/workflows/real_estate/__init__.py +0 -0
  266. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system.egg-info/SOURCES.txt +0 -0
  267. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system.egg-info/dependency_links.txt +0 -0
  268. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system.egg-info/entry_points.txt +0 -0
  269. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system.egg-info/requires.txt +0 -0
  270. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/smart_spatial_system.egg-info/top_level.txt +0 -0
  271. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/templates/__init__.py +0 -0
  272. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/templates/reports/__init__.py +0 -0
  273. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/templates/reports/real_estate_report.html +0 -0
  274. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_accessibility_query_spec.py +0 -0
  275. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_api_auth.py +0 -0
  276. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_api_contract_smoke.py +0 -0
  277. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_api_data_source_connectors_e2e.py +0 -0
  278. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_api_map_layers.py +0 -0
  279. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_api_mvp.py +0 -0
  280. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_api_outputs.py +0 -0
  281. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_api_projects.py +0 -0
  282. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_api_structured_error_normalization.py +0 -0
  283. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_api_upload_plugin_resolver.py +0 -0
  284. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_api_uploads.py +0 -0
  285. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_area_perimeter_calc.py +0 -0
  286. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_attribute_statistics.py +0 -0
  287. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_band_math.py +0 -0
  288. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_buffer_analysis.py +0 -0
  289. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_centroid_extractor.py +0 -0
  290. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_cli.py +0 -0
  291. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_crs_transformer.py +0 -0
  292. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_data_source_service.py +0 -0
  293. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_data_writer_exporter.py +0 -0
  294. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_deterministic_planner.py +0 -0
  295. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_dissolve_aggregator.py +0 -0
  296. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_document_file_report_contract.py +0 -0
  297. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_end_to_end_natural_query_pipeline.py +0 -0
  298. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_error_contract.py +0 -0
  299. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_feature_enrichment.py +0 -0
  300. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_frontend_api_surface_contract.py +0 -0
  301. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_geocoding_resolver.py +0 -0
  302. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_geocoding_resolver_error_redaction.py +0 -0
  303. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_geometry_validator.py +0 -0
  304. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_input_error_mapping.py +0 -0
  305. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_input_reference_resolver.py +0 -0
  306. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_input_reference_resolver_contract.py +0 -0
  307. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_kernel_artifacts.py +0 -0
  308. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_kernel_execution_bridge.py +0 -0
  309. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_kernel_plan_adapter.py +0 -0
  310. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_llm_intent_adapter.py +0 -0
  311. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_llm_raster_queryspec_normalization.py +0 -0
  312. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_llm_spec_generator_prenormalize.py +0 -0
  313. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_llm_spec_generator_semantic_context.py +0 -0
  314. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_llm_spec_generator_semantic_query_database_enrich.py +0 -0
  315. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_llm_spec_generator_semantic_queryspec_repair.py +0 -0
  316. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_loader_plugin_contract.py +0 -0
  317. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_local_path_validation.py +0 -0
  318. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_local_raster_loader.py +0 -0
  319. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_local_raster_loader_contract.py +0 -0
  320. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_local_vector_loader.py +0 -0
  321. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_local_vector_loader_contract.py +0 -0
  322. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_map_layer_contract.py +0 -0
  323. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_map_layer_service.py +0 -0
  324. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_ndvi_calculator.py +0 -0
  325. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_numeric_validation.py +0 -0
  326. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_audit.py +0 -0
  327. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_audit_integration.py +0 -0
  328. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_data_source_service_integration.py +0 -0
  329. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_feedback.py +0 -0
  330. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_feedback_integration.py +0 -0
  331. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_keyword_scoring_router.py +0 -0
  332. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_learning_signals.py +0 -0
  333. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_learning_signals_integration.py +0 -0
  334. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_llm_gate.py +0 -0
  335. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_llm_gate_integration.py +0 -0
  336. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_map_layer_service_integration.py +0 -0
  337. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_natural_query_pipeline.py +0 -0
  338. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_output_service_integration.py +0 -0
  339. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_production_response.py +0 -0
  340. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_production_response_integration.py +0 -0
  341. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_project_service_integration.py +0 -0
  342. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_query_execution_service_integration.py +0 -0
  343. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_registry_router.py +0 -0
  344. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_router_decision.py +0 -0
  345. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_router_decision_integration.py +0 -0
  346. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_routing_aware_plan_builder.py +0 -0
  347. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_runtime_paths.py +0 -0
  348. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_service.py +0 -0
  349. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_service_domain_boundary_contract.py +0 -0
  350. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_service_integration.py +0 -0
  351. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_service_postgis_dedup_contract.py +0 -0
  352. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_statistics.py +0 -0
  353. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_statistics_integration.py +0 -0
  354. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_upload_service_integration.py +0 -0
  355. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_weight_proposals.py +0 -0
  356. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_weight_proposals_integration.py +0 -0
  357. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_weight_store_persistence.py +0 -0
  358. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_weight_store_persistence_integration.py +0 -0
  359. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_weighted_router.py +0 -0
  360. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_orchestrator_weighted_router_integration.py +0 -0
  361. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_output_service.py +0 -0
  362. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_output_storage.py +0 -0
  363. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_pdf_renderer.py +0 -0
  364. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_phase3_kernel_registry_coverage.py +0 -0
  365. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_phase3_output_parity.py +0 -0
  366. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_phase3_postgis_provider_kernel_execution.py +0 -0
  367. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_planning_dag_executor.py +0 -0
  368. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_planning_dag_executor_async_capability.py +0 -0
  369. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_planning_error_mapping.py +0 -0
  370. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_planning_execution_policy.py +0 -0
  371. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_planning_raster_op_catalog_mapping.py +0 -0
  372. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_planning_raster_queryspec_execution.py +0 -0
  373. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_planning_registry_backed_raster_execution.py +0 -0
  374. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_planning_registry_backed_real_estate_execution.py +0 -0
  375. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_planning_runner.py +0 -0
  376. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_plugin_boundary_contract.py +0 -0
  377. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_plugin_config.py +0 -0
  378. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_plugin_config_store.py +0 -0
  379. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_plugin_error_mapping.py +0 -0
  380. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_plugin_modules.py +0 -0
  381. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_postgis_connector.py +0 -0
  382. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_postgis_connector_percent_escape.py +0 -0
  383. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_postgis_semantic_resolver.py +0 -0
  384. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_project_service.py +0 -0
  385. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_project_store.py +0 -0
  386. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_provider_error_mapping.py +0 -0
  387. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_query_dispatch_domain_boundary_contract.py +0 -0
  388. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_query_execution_postgis_planning_context.py +0 -0
  389. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_query_execution_service.py +0 -0
  390. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_query_execution_service_domain_import_boundary_contract.py +0 -0
  391. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_query_response_shape_golden.py +0 -0
  392. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_query_spec_enrichment.py +0 -0
  393. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_raster_capability_registry_contract.py +0 -0
  394. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_raster_clip_mask.py +0 -0
  395. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_raster_reclassify.py +0 -0
  396. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_raster_statistics.py +0 -0
  397. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_raster_threshold.py +0 -0
  398. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_raster_to_vector.py +0 -0
  399. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_real_estate_ranking_bridge.py +0 -0
  400. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_real_estate_ranking_golden.py +0 -0
  401. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_real_estate_ranking_query_spec_planning.py +0 -0
  402. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_real_estate_scoring_plugin.py +0 -0
  403. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_real_estate_spatial_enrichment_plugin.py +0 -0
  404. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_real_estate_spatial_helpers.py +0 -0
  405. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_report_builder.py +0 -0
  406. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_report_spec.py +0 -0
  407. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_request_document_download_contract.py +0 -0
  408. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_response_assembler.py +0 -0
  409. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_response_output_contract.py +0 -0
  410. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_risk_enrichment.py +0 -0
  411. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_runtime_paths.py +0 -0
  412. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_semantic_planning_context.py +0 -0
  413. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_service_auto_postgis_semantic_context.py +0 -0
  414. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_service_planning_artifacts.py +0 -0
  415. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_service_postgis_runtime_connection_injection.py +0 -0
  416. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_service_semantic_planning_context.py +0 -0
  417. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_service_strict_loader_contract.py +0 -0
  418. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_service_structured_error_normalization.py +0 -0
  419. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_slope_aspect.py +0 -0
  420. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_spatial_intersection.py +0 -0
  421. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_spatial_join.py +0 -0
  422. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_spatial_query_filter.py +0 -0
  423. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_spectral_indices.py +0 -0
  424. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_system_status_query_handler.py +0 -0
  425. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_upload_service.py +0 -0
  426. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_upload_storage.py +0 -0
  427. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_vector_display_handler.py +0 -0
  428. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_vector_geojson_helpers.py +0 -0
  429. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_vector_query_classifier.py +0 -0
  430. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_wms_wfs_fetcher.py +0 -0
  431. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/tests/test_wms_wfs_fetcher_error_redaction.py +0 -0
  432. {smart_spatial_system-0.2.2 → smart_spatial_system-0.2.4}/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.2
3
+ Version: 0.2.4
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
@@ -14,6 +14,7 @@ drop_failed: false
14
14
 
15
15
  # Optional CRS hint. Does not transform data.
16
16
  source_crs: null
17
+ target_crs: null
17
18
  warn_if_geographic_crs: true
18
19
 
19
20
  fields:
@@ -5,6 +5,7 @@ preserve_properties: true
5
5
  drop_failed: false
6
6
 
7
7
  source_crs: null
8
+ target_crs: null
8
9
  warn_if_geographic_crs: true
9
10
 
10
11
  fields:
@@ -15,6 +15,7 @@ drop_unmatched: false
15
15
  include_target_geometry: false
16
16
 
17
17
  source_crs: null
18
+ target_crs: null
18
19
  warn_if_geographic_crs: true
19
20
 
20
21
  fields:
@@ -7,6 +7,7 @@ drop_unmatched: false
7
7
  include_target_geometry: false
8
8
 
9
9
  source_crs: null
10
+ target_crs: null
10
11
  warn_if_geographic_crs: true
11
12
 
12
13
  fields:
@@ -1023,6 +1023,25 @@ Pending operations, not executable yet:
1023
1023
  {pending}
1024
1024
 
1025
1025
  Important mappings:
1026
+ - CRITICAL - any distance/nearest-neighbor operation (filter_by_distance,
1027
+ spatial_nearest, nearest_neighbor, distance_to) needs BOTH of its vector
1028
+ inputs reprojected with crs_transform first, not just the source/site
1029
+ layer. Distance is computed from raw geometry coordinates with zero CRS
1030
+ awareness - if one layer is reprojected to a metric CRS and the other is
1031
+ left in whatever CRS it was uploaded in (commonly EPSG:4326), the
1032
+ "distance" returned is a number between two points in DIFFERENT CRSs,
1033
+ meaningless but not an error by itself. Reproject EVERY layer that feeds
1034
+ a distance operation to the SAME target CRS, and pass that CRS as both
1035
+ source_crs and target_crs on the distance operation itself - this lets
1036
+ the operation catch a mismatch and raise instead of returning a bogus
1037
+ value:
1038
+ crs_transform(sites) -> sites_metric (target_crs="EPSG:31256")
1039
+ crs_transform(metro) -> metro_metric (target_crs="EPSG:31256")
1040
+ spatial_nearest(source=sites_metric, target=metro_metric,
1041
+ params={{"source_crs": "EPSG:31256", "target_crs": "EPSG:31256"}})
1042
+ WRONG: spatial_nearest(source=sites_metric, target=metro) - "metro" was
1043
+ never reprojected, so its coordinates are still in the original CRS.
1044
+
1026
1045
  - "nearer than X meters to POI":
1027
1046
  op="filter_by_distance"
1028
1047
  inputs={{"vector": "<source>", "reference": "<poi>"}}
@@ -1052,6 +1071,21 @@ Important mappings:
1052
1071
  - "score/rank":
1053
1072
  use score_features then rank_features.
1054
1073
 
1074
+ - CRITICAL - every scoring factor MUST include an explicit "type". There is
1075
+ NO default - a factor with no "type" is rejected, it does not fall back
1076
+ to anything. (An earlier version of this system defaulted a missing
1077
+ "type" to "boolean" silently; for a distance field that meant every
1078
+ score came out 0.0 for every feature, with no error - that default no
1079
+ longer exists.) Valid types: "boolean", "boolean_bonus",
1080
+ "inverse_distance", "risk_level", "inverse_level", "threshold",
1081
+ "condition", "direct", "numeric", "inverse_numeric". A distance field
1082
+ (anything you computed with spatial_nearest/nearest_neighbor/distance_to)
1083
+ needs "type": "inverse_distance" and a numeric "max_distance":
1084
+ {{"name": "near_metro", "field": "distance_to_metro",
1085
+ "type": "inverse_distance", "max_distance": 800, "weight": 1}}
1086
+ WRONG (missing "type" - rejected, not defaulted):
1087
+ {{"field": "distance_to_metro", "weight": -1}}
1088
+
1055
1089
  - CRITICAL - scoring against MORE THAN ONE computed field (e.g. distance to
1056
1090
  several different amenities/references): each computation must be CHAINED
1057
1091
  onto the previous one's output, not all computed separately from the
@@ -1667,12 +1701,12 @@ def _validate_operation_input_roles(spec: QuerySpec) -> None:
1667
1701
  _NEAREST_OPS_WITH_DISTANCE_FIELD = {"spatial_nearest", "nearest_neighbor", "filter_by_distance"}
1668
1702
 
1669
1703
 
1670
- def _extract_scoring_factor_fields(params: dict[str, Any]) -> list[str]:
1704
+ def _extract_scoring_factors(params: dict[str, Any]) -> list[dict[str, Any]]:
1671
1705
  """
1672
- Pull the "field" name out of every factor a score_features op's
1673
- params declare, across the shapes _normalize_scoring_spec (in
1674
- plugins/feature_scoring.py) accepts: top-level "factors", or
1675
- "scoring_spec.factors", or the older nested "scoring_spec.scoring.factors".
1706
+ Pull the raw factor dicts out of a score_features op's params, across
1707
+ the shapes _normalize_scoring_spec (in plugins/feature_scoring.py)
1708
+ accepts: top-level "factors", or "scoring_spec.factors", or the older
1709
+ nested "scoring_spec.scoring.factors".
1676
1710
  """
1677
1711
  factors = params.get("factors")
1678
1712
 
@@ -1688,10 +1722,19 @@ def _extract_scoring_factor_fields(params: dict[str, Any]) -> list[str]:
1688
1722
  if not isinstance(factors, list):
1689
1723
  return []
1690
1724
 
1725
+ return [factor for factor in factors if isinstance(factor, dict)]
1726
+
1727
+
1728
+ def _extract_scoring_factor_fields(params: dict[str, Any]) -> list[str]:
1729
+ """
1730
+ Pull the "field" name out of every factor a score_features op's
1731
+ params declare - see _extract_scoring_factors for the shapes this
1732
+ covers.
1733
+ """
1691
1734
  return [
1692
1735
  str(factor["field"])
1693
- for factor in factors
1694
- if isinstance(factor, dict) and factor.get("field")
1736
+ for factor in _extract_scoring_factors(params)
1737
+ if factor.get("field")
1695
1738
  ]
1696
1739
 
1697
1740
 
@@ -1751,6 +1794,64 @@ def _ancestor_refs(start_ref: str, ops_by_output: dict[str, OperationSpec]) -> s
1751
1794
  return seen
1752
1795
 
1753
1796
 
1797
+ # Kept in sync by hand with plugins/feature_scoring.py's _score_factor -
1798
+ # there is no single source of truth to generate this from (unlike
1799
+ # OP_CATALOG for operations), so a new factor type added there needs
1800
+ # adding here too.
1801
+ _VALID_SCORING_FACTOR_TYPES = {
1802
+ "boolean",
1803
+ "boolean_bonus",
1804
+ "inverse_distance",
1805
+ "risk_level",
1806
+ "inverse_level",
1807
+ "threshold",
1808
+ "condition",
1809
+ "direct",
1810
+ "numeric",
1811
+ "inverse_numeric",
1812
+ }
1813
+
1814
+
1815
+ def _validate_score_features_factor_types(spec: QuerySpec) -> None:
1816
+ """
1817
+ Catch a score_features factor with no "type" before the plan is
1818
+ returned, not when it silently scores everything 0.0.
1819
+
1820
+ plugins/feature_scoring.py's _score_factor has no default for a
1821
+ missing "type" (it raises) - but that only fires at execution time,
1822
+ several steps and possibly minutes of API-billed retries away from
1823
+ the generation step that produced the bad spec. This catches the
1824
+ identical condition immediately, with the same "there is no safe
1825
+ default" reasoning, right where the LLM's output is still available
1826
+ to name in the error.
1827
+ """
1828
+ for op in spec.operations:
1829
+ if op.op != "score_features":
1830
+ continue
1831
+
1832
+ for factor in _extract_scoring_factors(op.params):
1833
+ factor_type = factor.get("type")
1834
+ field_name = factor.get("field") or factor.get("name") or "<unnamed>"
1835
+
1836
+ if not factor_type:
1837
+ raise LLMSpecGenerationError(
1838
+ f"score_features (output={op.output!r}) has a factor "
1839
+ f"for field {field_name!r} with no 'type'. There is no "
1840
+ "safe default - every factor must specify one "
1841
+ f"explicitly: {sorted(_VALID_SCORING_FACTOR_TYPES)!r}. "
1842
+ "A distance field almost always wants "
1843
+ "'inverse_distance' with 'max_distance' set."
1844
+ )
1845
+
1846
+ if factor_type not in _VALID_SCORING_FACTOR_TYPES:
1847
+ raise LLMSpecGenerationError(
1848
+ f"score_features (output={op.output!r}) has a factor "
1849
+ f"for field {field_name!r} with unsupported type "
1850
+ f"{factor_type!r}. Valid types: "
1851
+ f"{sorted(_VALID_SCORING_FACTOR_TYPES)!r}."
1852
+ )
1853
+
1854
+
1754
1855
  def _validate_score_features_field_chaining(spec: QuerySpec) -> None:
1755
1856
  """
1756
1857
  Catch a score_features op reading from a ref that never accumulated a
@@ -1820,6 +1921,124 @@ def _validate_score_features_field_chaining(spec: QuerySpec) -> None:
1820
1921
  )
1821
1922
 
1822
1923
 
1924
+ # The two vector-bearing input roles for each distance/nearest-neighbor
1925
+ # operation, in (this-layer, other-layer) order - used to check that both
1926
+ # were reprojected to the same CRS, not just one of them.
1927
+ _DISTANCE_OPS_VECTOR_ROLES = {
1928
+ "spatial_nearest": ("source", "target"),
1929
+ "nearest_neighbor": ("source", "target"),
1930
+ "filter_by_distance": ("vector", "reference"),
1931
+ "distance_to": ("vector", "target"),
1932
+ }
1933
+
1934
+
1935
+ def _crs_transform_target_crs(
1936
+ ref: str, ops_by_output: dict[str, OperationSpec]
1937
+ ) -> str | None:
1938
+ """
1939
+ The target_crs a ref was reprojected to - either directly (ref is the
1940
+ output of a crs_transform operation), or inherited by walking back
1941
+ through a chain of distance/nearest-neighbor operations on their
1942
+ source side, since those operations don't reproject and so preserve
1943
+ whatever CRS their source input was already in.
1944
+
1945
+ That chain-walk matters for exactly the case
1946
+ accessibility_query_spec.py's own multi-amenity chain produces (and
1947
+ any equivalent LLM-generated chain): only the FIRST spatial_nearest
1948
+ step's source is directly a crs_transform output -
1949
+ "sites_metric" -> spatial_nearest(metro) -> "sites_with_metro" ->
1950
+ spatial_nearest(schools, source="sites_with_metro") -> ... - every
1951
+ later step's source is the previous step's output, not a
1952
+ crs_transform output. An earlier version of this function checked
1953
+ only the literal ref and treated every one of those later steps as
1954
+ "not traceable", which made this validator raise on a plan that was
1955
+ completely correct - caught by testing this exact function against
1956
+ accessibility_query_spec.py's own generated chain, not by inspection.
1957
+
1958
+ Still deliberately narrow on the OTHER side, though: this only walks
1959
+ through the vector-preserving "source" role of a chain of distance
1960
+ ops, never through a join, a filter combining two layers, or any
1961
+ other operation that doesn't obviously preserve a single input's CRS -
1962
+ those remain untraceable (None), which is the conservative direction
1963
+ to be wrong in.
1964
+ """
1965
+ op = ops_by_output.get(ref)
1966
+ if op is None:
1967
+ return None
1968
+
1969
+ if op.op == "crs_transform":
1970
+ target_crs = op.params.get("target_crs")
1971
+ return str(target_crs) if target_crs else None
1972
+
1973
+ roles = _DISTANCE_OPS_VECTOR_ROLES.get(op.op)
1974
+ if roles is not None:
1975
+ this_role, _other_role = roles
1976
+ upstream_ref = op.inputs.get(this_role)
1977
+ if upstream_ref:
1978
+ return _crs_transform_target_crs(str(upstream_ref), ops_by_output)
1979
+
1980
+ return None
1981
+
1982
+
1983
+ def _validate_distance_op_crs_symmetry(spec: QuerySpec) -> None:
1984
+ """
1985
+ Catch a distance/nearest-neighbor operation whose two vector inputs
1986
+ were reprojected asymmetrically - one just-reprojected via
1987
+ crs_transform, the other not (or reprojected to a different CRS).
1988
+
1989
+ Distance here is computed from raw geometry coordinates with zero CRS
1990
+ awareness (see calculate_distances/find_nearest_neighbors). Reprojecting
1991
+ only the source/site layer and leaving the target/amenity layer in its
1992
+ original CRS - typically EPSG:4326 from the source upload - produces a
1993
+ "distance" between two points in different CRSs: a large, consistent,
1994
+ completely bogus number, not an error, because nothing before this
1995
+ check ever compared the two layers' actual CRSs.
1996
+
1997
+ Deliberately conservative, same posture as
1998
+ _validate_score_features_field_chaining: only fires when this module
1999
+ can see BOTH refs' immediate CRS provenance disagree (see
2000
+ _crs_transform_target_crs's docstring for exactly what "immediate"
2001
+ means here). A ref this module can't trace to a crs_transform output
2002
+ at all - already in a metric CRS from its source, for instance - is
2003
+ left unvalidated rather than guessed at.
2004
+ """
2005
+ ops_by_output: dict[str, OperationSpec] = {
2006
+ op.output: op for op in spec.operations if op.output
2007
+ }
2008
+
2009
+ for op in spec.operations:
2010
+ roles = _DISTANCE_OPS_VECTOR_ROLES.get(op.op)
2011
+ if roles is None:
2012
+ continue
2013
+
2014
+ this_role, other_role = roles
2015
+ this_ref = op.inputs.get(this_role)
2016
+ other_ref = op.inputs.get(other_role)
2017
+ if not this_ref or not other_ref:
2018
+ continue
2019
+
2020
+ this_crs = _crs_transform_target_crs(str(this_ref), ops_by_output)
2021
+ other_crs = _crs_transform_target_crs(str(other_ref), ops_by_output)
2022
+
2023
+ if this_crs is None and other_crs is None:
2024
+ continue
2025
+
2026
+ if this_crs == other_crs:
2027
+ continue
2028
+
2029
+ raise LLMSpecGenerationError(
2030
+ f"{op.op!r} (output={op.output!r}) reads {this_role}={this_ref!r} "
2031
+ f"(reprojected to {this_crs!r}) and {other_role}={other_ref!r} "
2032
+ f"(reprojected to {other_crs!r}) - these do not match. Every "
2033
+ "layer feeding a distance/nearest-neighbor operation must be "
2034
+ "reprojected with crs_transform to the SAME target CRS before "
2035
+ "the operation runs, or the resulting distance is computed "
2036
+ "between points in two different CRSs and is meaningless. See "
2037
+ "the 'any distance/nearest-neighbor operation needs BOTH of "
2038
+ "its vector inputs reprojected' guidance."
2039
+ )
2040
+
2041
+
1823
2042
  class LLMQuerySpecGenerator:
1824
2043
  def __init__(
1825
2044
  self,
@@ -1868,7 +2087,9 @@ class LLMQuerySpecGenerator:
1868
2087
  spec = query_spec_from_dict(data, raw_query_fallback=raw_query)
1869
2088
  spec = normalize_llm_query_spec_for_planning(spec)
1870
2089
  _validate_operation_input_roles(spec)
2090
+ _validate_score_features_factor_types(spec)
1871
2091
  _validate_score_features_field_chaining(spec)
2092
+ _validate_distance_op_crs_symmetry(spec)
1872
2093
  return spec
1873
2094
 
1874
2095
 
@@ -85,6 +85,10 @@ _NEAREST_PARAM_MAP = {
85
85
  "precision": "precision",
86
86
  "include_target_geometry": "include_target_geometry",
87
87
  "source_crs": "source_crs",
88
+ # Passing both source_crs and target_crs lets find_nearest_neighbors
89
+ # catch a source/target CRS mismatch and raise instead of silently
90
+ # computing a meaningless planar distance - see its docstring.
91
+ "target_crs": "target_crs",
88
92
  # Lets a plan chain several nearest-neighbour steps over the same
89
93
  # features, each writing its own distance field - see the capability's
90
94
  # docstring.
@@ -342,6 +346,10 @@ OP_CATALOG: dict[str, OpDescriptor] = {
342
346
  "precision": "precision",
343
347
  "drop_failed": "drop_failed",
344
348
  "source_crs": "source_crs",
349
+ # Passing both source_crs and target_crs lets calculate_distances
350
+ # catch a source/target CRS mismatch and raise instead of
351
+ # silently computing a meaningless planar distance.
352
+ "target_crs": "target_crs",
345
353
  "metadata": "metadata",
346
354
  },
347
355
  output_type="vector",
@@ -713,6 +713,51 @@ def _is_geographic_crs(value: Any) -> bool:
713
713
  }
714
714
 
715
715
 
716
+ def _raise_if_crs_mismatch(
717
+ *,
718
+ source_crs: str | None,
719
+ target_crs: str | None,
720
+ capability_name: str,
721
+ ) -> None:
722
+ """
723
+ Raise if source_crs and target_crs are both supplied and don't match.
724
+
725
+ Distance/nearest-neighbor calculation here works on raw geometry
726
+ coordinates with zero CRS awareness - it has no way to notice on its
727
+ own that source_features and target_features are in different CRSs
728
+ (e.g. only the source layer was reprojected with crs_transform before
729
+ this call, or the two calls in a plan used different target CRSs).
730
+ Left unchecked, that produces a number - not an error - that is
731
+ physically meaningless: a planar distance between a point in metres
732
+ and a point in degrees, indistinguishable from a real distance
733
+ without inspecting the value by hand. This is opt-in (only checked
734
+ when the caller supplies BOTH hints) rather than required, so callers
735
+ that don't pass CRS hints at all keep today's behaviour unchanged.
736
+
737
+ Comparison is a normalized (stripped, uppercased) string match, not
738
+ true CRS equivalence - "EPSG:4326" and "CRS:84" describe the same CRS
739
+ but won't match each other here. That is a deliberately conservative
740
+ trade-off: false negatives (a real mismatch expressed as equivalent-
741
+ but-differently-spelled CRSs, missed) are possible, but false
742
+ positives (correctly matching CRSs rejected) are not, since this
743
+ module has no CRS-equivalence table to consult.
744
+ """
745
+ if not source_crs or not target_crs:
746
+ return
747
+
748
+ if str(source_crs).strip().upper() == str(target_crs).strip().upper():
749
+ return
750
+
751
+ raise ValueError(
752
+ f"{capability_name}: source_crs={source_crs!r} and "
753
+ f"target_crs={target_crs!r} do not match. Computing distance "
754
+ "between features in two different CRSs produces a meaningless "
755
+ "number, not an error - reproject both source_features and "
756
+ "target_features to the same CRS with crs_transform first, then "
757
+ "pass matching source_crs/target_crs here."
758
+ )
759
+
760
+
716
761
  def _make_distance_feature(
717
762
  *,
718
763
  source_feature: dict[str, Any],
@@ -846,6 +891,7 @@ def _build_vector_metadata(features: list[dict[str, Any]]) -> dict[str, Any]:
846
891
  "precision",
847
892
  "drop_failed",
848
893
  "source_crs",
894
+ "target_crs",
849
895
  "metadata",
850
896
  ],
851
897
  output_kind="vector",
@@ -871,6 +917,7 @@ def calculate_distances(
871
917
  precision: int | None = None,
872
918
  drop_failed: bool | None = None,
873
919
  source_crs: str | None = None,
920
+ target_crs: str | None = None,
874
921
  metadata: dict[str, Any] | None = None,
875
922
  ) -> VectorOut:
876
923
  """
@@ -890,7 +937,19 @@ def calculate_distances(
890
937
  drop_failed:
891
938
  If True, failed source/pair results are removed.
892
939
  source_crs:
893
- CRS hint. Used only for warning metadata.
940
+ CRS hint for source_features.
941
+ target_crs:
942
+ CRS hint for target_features.
943
+
944
+ Distance here is computed from raw geometry coordinates with
945
+ no CRS awareness at all - if source_features and
946
+ target_features are actually in different CRSs, the result is
947
+ a number, not an error: meaningless, but indistinguishable
948
+ from a real distance without inspecting it by hand. Supplying
949
+ both source_crs and target_crs lets this function catch that
950
+ case and raise instead of returning it. Neither hint changes
951
+ how distance is computed; only crs_transform actually
952
+ reprojects data.
894
953
  metadata:
895
954
  Optional metadata to merge.
896
955
 
@@ -920,8 +979,15 @@ def calculate_distances(
920
979
  )
921
980
 
922
981
  final_source_crs = pick_first(source_crs, config.get("source_crs"), default=None)
982
+ final_target_crs = pick_first(target_crs, config.get("target_crs"), default=None)
923
983
  warn_if_geographic_crs = bool(config.get("warn_if_geographic_crs", True))
924
984
 
985
+ _raise_if_crs_mismatch(
986
+ source_crs=final_source_crs,
987
+ target_crs=final_target_crs,
988
+ capability_name="calculate_distances",
989
+ )
990
+
925
991
  preserve_properties = bool(config.get("preserve_properties", True))
926
992
  fields = _configured_fields(config)
927
993
 
@@ -1102,6 +1168,7 @@ def calculate_distances(
1102
1168
  "coordinate_precision": final_precision,
1103
1169
  "drop_failed": final_drop_failed,
1104
1170
  "source_crs": final_source_crs,
1171
+ "target_crs": final_target_crs,
1105
1172
  "planar_only": True,
1106
1173
  "warning": geographic_warning,
1107
1174
  "source_feature_count": len(source_items),
@@ -228,7 +228,29 @@ def _score_factor(properties: dict[str, Any], factor: dict[str, Any]) -> tuple[f
228
228
  if not isinstance(factor, dict):
229
229
  raise ValueError("Each scoring factor must be a dict.")
230
230
 
231
- factor_type = str(factor.get("type") or "boolean")
231
+ raw_factor_type = factor.get("type")
232
+ if not raw_factor_type:
233
+ # A missing "type" used to default to "boolean" silently. For any
234
+ # factor scoring a non-boolean field - a distance, most commonly -
235
+ # that produces a wrong, near-constant score (0.0 whenever the
236
+ # field is falsy, which for a distance means "exactly zero") with
237
+ # no error at all: this is how a whole batch of LLM-generated
238
+ # scoring specs that omitted "type" on a distance factor came out
239
+ # 0.0 for every feature, indistinguishable from a real degenerate
240
+ # result. "boolean" is a valid, explicit choice (still supported
241
+ # below) - it must never be the unstated default for a field whose
242
+ # actual meaning this function has no way to guess.
243
+ field_name = factor.get("field") or factor.get("name") or "<unnamed>"
244
+ raise ValueError(
245
+ f"Scoring factor for field {field_name!r} has no 'type'. There "
246
+ "is no safe default - specify one explicitly: 'boolean', "
247
+ "'boolean_bonus', 'inverse_distance', 'risk_level', "
248
+ "'inverse_level', 'threshold', 'condition', 'direct', "
249
+ "'numeric', or 'inverse_numeric'. A distance field almost "
250
+ "always wants 'inverse_distance' with 'max_distance' set."
251
+ )
252
+
253
+ factor_type = str(raw_factor_type)
232
254
  name = str(factor.get("name") or factor.get("field") or factor_type)
233
255
  field = str(factor.get("field") or "")
234
256
  value = _get_property(properties, field) if field else None
@@ -45,6 +45,7 @@ from plugins.distance_calculator import (
45
45
  _calculate_distance,
46
46
  _geometry_bbox,
47
47
  _is_geographic_crs,
48
+ _raise_if_crs_mismatch,
48
49
  _validate_engine,
49
50
  )
50
51
 
@@ -356,6 +357,7 @@ def _build_vector_metadata(features: list[dict[str, Any]]) -> dict[str, Any]:
356
357
  "drop_unmatched",
357
358
  "include_target_geometry",
358
359
  "source_crs",
360
+ "target_crs",
359
361
  "metadata",
360
362
  ],
361
363
  output_kind="vector",
@@ -383,6 +385,7 @@ def find_nearest_neighbors(
383
385
  drop_unmatched: bool | None = None,
384
386
  include_target_geometry: bool | None = None,
385
387
  source_crs: str | None = None,
388
+ target_crs: str | None = None,
386
389
  distance_field: str | None = None,
387
390
  metadata: dict[str, Any] | None = None,
388
391
  ) -> VectorOut:
@@ -407,7 +410,20 @@ def find_nearest_neighbors(
407
410
  include_target_geometry:
408
411
  If True, target geometry is copied into output properties.
409
412
  source_crs:
410
- CRS hint. Used only for warning metadata.
413
+ CRS hint for source_features.
414
+ target_crs:
415
+ CRS hint for target_features.
416
+
417
+ Distance here is computed from raw geometry coordinates with no
418
+ CRS awareness at all - if source_features and target_features
419
+ are actually in different CRSs (e.g. only one of them was
420
+ reprojected with crs_transform before this call), the result
421
+ is a number, not an error: meaningless, but indistinguishable
422
+ from a real distance without inspecting it by hand. Supplying
423
+ both source_crs and target_crs lets this function catch that
424
+ case and raise instead of returning it - see the raise below.
425
+ Neither hint changes how distance is computed; only
426
+ crs_transform actually reprojects data.
411
427
  distance_field:
412
428
  Optional output field name for the computed distance,
413
429
  overriding the configured default (config/plugins/
@@ -460,8 +476,15 @@ def find_nearest_neighbors(
460
476
  )
461
477
 
462
478
  final_source_crs = pick_first(source_crs, config.get("source_crs"), default=None)
479
+ final_target_crs = pick_first(target_crs, config.get("target_crs"), default=None)
463
480
  warn_if_geographic_crs = bool(config.get("warn_if_geographic_crs", True))
464
481
 
482
+ _raise_if_crs_mismatch(
483
+ source_crs=final_source_crs,
484
+ target_crs=final_target_crs,
485
+ capability_name="find_nearest_neighbors",
486
+ )
487
+
465
488
  preserve_properties = bool(config.get("preserve_properties", True))
466
489
  fields = _configured_fields(config)
467
490
 
@@ -594,6 +617,7 @@ def find_nearest_neighbors(
594
617
  "drop_unmatched": final_drop_unmatched,
595
618
  "include_target_geometry": final_include_target_geometry,
596
619
  "source_crs": final_source_crs,
620
+ "target_crs": final_target_crs,
597
621
  "planar_only": True,
598
622
  "warning": geographic_warning,
599
623
  "source_feature_count": len(source_items),
@@ -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.2"
15
+ version = "0.2.4"
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"
@@ -191,7 +191,17 @@ def build_accessibility_query_spec(
191
191
  OperationSpec(
192
192
  op="nearest_neighbor",
193
193
  inputs={"source": current_sites_ref, "target": amenity_metric_ref},
194
- params={"k": 1, "distance_field": amenity.distance_field},
194
+ # Both sides were just reprojected to target_crs above, so
195
+ # these are always equal here - passed anyway so
196
+ # find_nearest_neighbors' own source/target CRS mismatch
197
+ # check (plugins/distance_calculator.py) protects this
198
+ # call too, not only hand-written or LLM-generated plans.
199
+ params={
200
+ "k": 1,
201
+ "distance_field": amenity.distance_field,
202
+ "source_crs": target_crs,
203
+ "target_crs": target_crs,
204
+ },
195
205
  output=enriched_ref,
196
206
  )
197
207
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: smart_spatial_system
3
- Version: 0.2.2
3
+ Version: 0.2.4
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