Define canonical GeoArrow spatial values across GraphForge query, storage, and bindings #797
Description
Activity
- addedenhancementNew feature or requestNew feature or requestcoreCore source code changesCore source code changes
on Aug 18, 2026 - changed the title
[-]Define canonical Arrow spatial values across GraphForge query, storage, and bindings[/-][+]Define canonical GeoArrow spatial values across GraphForge query, storage, and bindings[/+]on Aug 18, 2026 - added sub-issues
on Aug 18, 2026 - added this to the M7: Typed Spatial and Incremental Consumer Interoperability for v0.5.x milestone
on Aug 18, 2026 Canonical GeoArrow close gate is complete.
Native sub-issues and merge evidence:
- Define Arrow extension preservation and the GeoArrow value profile #799 closed by feat: define canonical GeoArrow spatial contract #806: canonical Arrow-extension and GeoArrow value profile.
- Persist, query, and profile canonical GeoArrow spatial properties #800 closed by Persist and query canonical GeoArrow spatial properties #814: scalar/bulk construction, persistence/reopen/query, computation profile, resource limits, and typed failures.
- Expose canonical GeoArrow values through Python, Node, and CLI #801 closed by feat(bindings): expose canonical GeoArrow interchange #817: thin Python/Node/CLI surfaces with real binding execution.
- Certify GeoArrow producer conformance and portability #802 closed by feat(spatial): certify GeoArrow producer portability #823: preserved-but-noncomputable extension/CRS transport through Arrow/storage/reopen/export, explicit point()/distance() failure, deterministic IPC/Parquet fixtures and fingerprints, malformed/adversarial coverage, documentation, and conformance evidence.
PR #823 merged from exact head 5d5aa56 after all 21 checks and CI Gate passed, merge state was CLEAN, and no review threads were unresolved. The complete diff remains Rust-owned with thin bindings and adds no visualization, XYG, map, tile, or foreign-engine dependency. This satisfies the canonical #797 acceptance outcomes and unblocks its native dependents.
Requirement-by-requirement close audit (merged-tree evidence):
- Normative producer profile/layout/metadata/CRS/edge/operation/deferred forms — feat: define canonical GeoArrow spatial contract #806 established the canonical value/profile contract; feat(spatial): certify GeoArrow producer portability #823 added
docs/book/architecture/geoarrow-conformance.mdand reconciledspatial-values.mdplus the interchange contract. - Lossless scalar/bulk → commit/reopen/query → IPC/Parquet/fingerprint/CLI/Python/Node — Persist and query canonical GeoArrow spatial properties #814 covers Rust scalar/bulk construction and persistence/reopen/query; feat(bindings): expose canonical GeoArrow interchange #817 executes thin Python, Node, and CLI paths; feat(spatial): certify GeoArrow producer portability #823 adds canonical Arrow IPC/Parquet artifacts, checksums, CLI export, and real binding conformance.
- Unsupported-but-well-formed extension/CRS round-trip — feat(spatial): certify GeoArrow producer portability #823 adds
SpatialCrs::Preserved, retains exact extension name/metadata in storage decode/write and reopen/query/export, with direct preserved-profile tests. - Stable typed unsupported-operation failures before partial output/mutation — Persist and query canonical GeoArrow spatial properties #814 establishes typed computation/resource failures; feat(spatial): certify GeoArrow producer portability #823 directly proves preserved-only
distance()and unsupported-CRSpoint()reject explicitly. - Atomic malformed/over-budget rejection without value-bearing diagnostics — feat: define canonical GeoArrow spatial contract #806/Persist and query canonical GeoArrow spatial properties #814 validate finite coordinates, layouts/nesting/metadata, point-distance and resource budgets before publish; feat(spatial): certify GeoArrow producer portability #823 adds malformed/adversarial conformance cases.
- Documented
point()/distance()matches direct Rust behavior — Persist and query canonical GeoArrow spatial properties #814 implements and tests the certified 4326/3857 surface; feat(spatial): certify GeoArrow producer portability #823 adds direct Rust rejection evidence for noncomputable preserved profiles and updates documentation. - Producer-neutral golden fixtures without renaming or row-wise reconstruction — feat(spatial): certify GeoArrow producer portability #823 adds deterministic
canonical.arrowandcanonical.parquet,SHA256SUMS, independent PyArrow reads, and exact metadata checks; canonical paths remain typed Arrow rather than WKB/WKT/GeoJSON. - No visualization/map/tile/scene/XYG behavior in GraphForge — merged diffs are confined to core/API/storage/plan/rel, thin bindings/CLI, fixtures/build metadata, and architecture docs; no XYG, renderer, map SDK, tile, scene, or foreign graph-engine dependency was introduced.
- Relevant exact-head CI Gate green — feat: define canonical GeoArrow spatial contract #806, Persist and query canonical GeoArrow spatial properties #814, feat(bindings): expose canonical GeoArrow interchange #817, and feat(spatial): certify GeoArrow producer portability #823 each merged only after exact-head gates. Final feat(spatial): certify GeoArrow producer portability #823 head
5d5aa56f61f2a090c28fb219ab4927f70cc4a61bpassed all 21 checks including CI Gate, both Bazel lanes, Rust Quality, Rust Benchmarks/CodSpeed, native Python/Node, concurrency, and storage platform lanes; merge state was CLEAN with zero unresolved threads.
Native graph audit: #799–#802 are all CLOSED sub-issues and CLOSED blockers of #797. #797 is CLOSED/COMPLETED and remains the native dependency of CurateLabs/xyg#47, CurateLabs/graphforge-vscode#82, and #810; those consumers now observe #797 as CLOSED.
- Normative producer profile/layout/metadata/CRS/edge/operation/deferred forms — feat: define canonical GeoArrow spatial contract #806 established the canonical value/profile contract; feat(spatial): certify GeoArrow producer portability #823 added
Problem
GraphForge is a consumer-neutral graph and knowledge workbench whose public data plane is Arrow, but it cannot yet represent, persist, query, and exchange standardized spatial values end to end. Ad hoc longitude/latitude columns cannot carry geometry type, CRS, edge interpretation, validity, or stable cross-language semantics.
GeoArrow is useful independently of any one renderer: notebooks, analytical consumers, dataframes, files, agents, and XYG should all receive the same typed spatial values. That does not make visualization behavior a GraphForge responsibility.
Objective
Define and ship strong, Rust-owned GeoArrow spatial values through GraphForge ontology, mutation, storage, query, Arrow interchange, and thin bindings while keeping rendering, viewport, projection UI, LOD, layers, paint, and interaction outside GraphForge.
Consumer-Neutral GeoArrow Contract
Point,LineString,Polygon,MultiPoint,MultiLineString, andMultiPolygon.point()/distance()surface; it must not create an unbounded GIS engine by implication.Requirements
Acceptance Criteria
point()anddistance()behavior is either implemented with direct Rust execution evidence under the certified profile or corrected precisely; no false completeness claim remains.BDD Completion Scenarios
Scenario: Spatial property crosses every GraphForge boundary
Given a node or edge with a canonical spatial property and explicit CRS
When it is committed, reopened, queried, and consumed through Python, Node, and CLI/export
Then every surface receives the same Arrow value, buffers, and metadata
And no binding reconstructs the geometry.
Scenario: Unknown computation profile remains transportable
Given a well-formed GeoArrow value whose CRS can be preserved but is not supported for a requested spatial operation
When the value is stored, queried, and exported
Then its extension and CRS metadata remain unchanged
And the unsupported operation returns a stable typed error without altering the value.
Scenario: Invalid spatial input fails atomically
Given malformed offsets/rings, non-finite coordinates, inconsistent metadata, or an over-budget geometry
When construction or query materialization validates it
Then GraphForge returns a stable typed error
And publishes no partial graph state or result.
Observability
Safe extension/geometry type, CRS-present flag or non-sensitive identifier, row/feature counts, byte counts, validation phase, and error code only. Never log coordinates, property values, queries, or paths.
Security And Privacy
Bound geometry sizes and nesting, validate metadata and offsets before allocation, preserve project/path containment, and perform no implicit network, tile, style, geocoding, or CRS-provider access.
Testing
Rust type/validation/property tests for every producer-profile geometry; scalar and bulk construction parity; create/query/reopen and accepted batch-boundary round trips; Arrow IPC and Parquet schema/buffer goldens; extension metadata and fingerprint checks; EPSG:4326/3857 operation cases; unsupported-but-preserved CRS cases; malformed offsets/rings, nulls, nesting, vertex/byte budgets; Python/Node/CLI parity; and producer-neutral fixtures.
Documentation
Update ontology/value, Cypher spatial function, Arrow, storage/project format, bindings, CLI/export, and compatibility documentation. Consumer-specific rendering instructions remain in the consumer repository.
Non-Goals
Maps, basemaps, tiles, viewport/projection UI, geographic LOD, layer geometry, paint, interaction, automatic geocoding, field inference, hidden CRS conversion, a full GIS/overlay engine, geometry collections, mixed geometry columns, Z/M production, or a GraphForge dependency on XYG.
Related Issues