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