Skip to content

Repository files navigation

GeoDebug

Find the geographic bug, not just the code bug.

GeoDebug:不让 Codex 在 GIS 上裸奔

Geospatial correctness checks for data and workflows.

CI Release License: MIT Python Typed

Architecture · Rule catalog · Failure cases · Contributing · Security · Changelog · Releases

GeoMole, the GeoDebug mascot inspecting a half-pixel raster grid offset

GeoMole · small offsets, big bugs.


Your file opens. Your geometry is valid. Your tests pass.

Your result can still be geographically wrong.

✓ file readable
✓ geometry valid
✓ pipeline completed
✓ tests passed
? geographically correct

GeoDebug checks the last question. It catches spatial-semantic failures that ordinary software tests and file validators can miss: CRS misuse, impossible coordinates, raster-grid misalignment, cross-dataset incompatibility, NoData/mask conflicts, and operations whose units do not mean what the code assumes.

See the gap

This workflow can run without raising a Python exception:

roads = gpd.read_file("roads.geojson")
buffered = roads.buffer(500)
buffered.to_file("roads_buffer.geojson")

But if the data uses a geographic CRS, 500 is interpreted in angular coordinate units rather than meters.

GeoDebug makes that failure explicit before the operation becomes a result:

$ geodebug preflight roads.geojson --operation buffer --distance 500

roads.geojson
ERROR GEO501  Buffer distance is interpreted in angular coordinate units.
  crs.kind: geographic
  crs.axis_units: degree, degree
  operation.distance: 500
1 error(s) · 0 warning(s) · 0 note(s) · 1 unknown

The code can be valid while the geography is not.

Install and see one failure immediately:

pip install geodebug
geodebug demo

Then check a dataset or preflight an operation:

geodebug check roads.geojson
geodebug preflight roads.geojson --operation buffer --distance 500

Where GeoDebug fits

Layer Question
Parser / schema Can the data be read and interpreted structurally?
Geometry validity Is the geometry structurally valid?
Software tests Does the program behave as specified?
GeoDebug Does the data or operation make geographic sense?

GeoDebug does not replace GDAL, GeoPandas, Shapely, Rasterio, or PyProj. It turns spatial facts exposed by the geospatial stack into a systematic, deterministic geospatial correctness layer with stable diagnostics that can run locally or in CI.

No LLM in the core. No silent CRS guessing. No automatic "fix everything."

GeoDebug architecture, diagnostic scopes, rule families, and CLI example

What it catches

GeoDebug is built for bugs that ordinary syntax checks and file validators often miss.

Domain Examples
CRS missing CRS, impossible angular coordinates, data outside a projected CRS area of use
Vector invalid geometry
Raster singular affine transforms, NoData/mask conflicts
Relations non-overlapping datasets, half-pixel raster grid shifts
Operations metric buffer, planar area, or planar distance on a geographic CRS

A file can be valid in isolation and still be wrong for the operation you are about to run. That distinction is the point.

Failure cases

Want the bugs, not the architecture?

Run five small failures that still produce valid-looking pipeline output. Read the field notes: 5 Geospatial Bugs That Valid Data and Passing Tests Won't Catch.

Two 10 meter rasters with identical values but a five meter half-pixel grid offset

Each case builds its own local fixture, runs the bad workflow, and is exercised in CI.

Mental model

source
  │
  ▼
adapter ──► facts ──► rules ──► diagnostics ──► report
                        ▲
                        │
              dataset / relation / operation

Three questions drive the engine:

  1. Dataset — is this dataset internally spatially plausible?
  2. Relation — are these datasets compatible with each other?
  3. Operation — is this operation semantically valid for these coordinates and units?

Adapters observe. Rules diagnose. Policy decides what fails the build.

CLI

Command Purpose
geodebug demo Run a built-in 500 m buffer failure
geodebug inspect DATA Show normalized spatial facts without diagnosing
geodebug check DATA Run dataset diagnostics
geodebug compare A B Run dataset + relational diagnostics
geodebug preflight DATA --operation ... Check operation semantics before execution
geodebug rules list Inspect the built-in rule corpus
geodebug schema Print the canonical report schema

Full geometry or raster scans are opt-in:

geodebug check landcover.tif --deep

Machine-readable output is first-class:

geodebug check roads.geojson --format json

Install

pip install geodebug
geodebug demo

Need every adapter:

pip install "geodebug[all]"

Optional extras keep the core small:

Extra Support
core GeoJSON
vector GeoPackage, Shapefile, FlatGeobuf
raster GeoTIFF, COG, VRT
parquet GeoParquet
geopandas in-memory GeoDataFrame
all all optional adapters

Requires Python 3.12+.

Diagnostic corpus

GeoDebug ships 11 built-in rules with stable IDs.

Family Rules
CRS GEO101 missing CRS · GEO103 coordinate range · GEO105 area of use
Vector GEO201 invalid geometry
Raster GEO301 affine transform · GEO304 NoData/mask conflict
Relations GEO402 spatial overlap · GEO404 grid alignment
Operations GEO501 buffer · GEO502 area · GEO503 distance/length

Every released rule has an explicit contract for PASS, FAIL, UNKNOWN, and NOT_APPLICABLE.

geodebug rules show GEO404

Project policy

Projects can tune severity, disable rules, and suppress known exceptions without changing rule truth values.

schema_version = "1"
profile = "default"
fail_on = "error"

[rules]
disable = []

[rules.severity]
GEO101 = "error"

[[suppress]]
rule = "GEO103"
path = "legacy/*.geojson"
reason = "Known upstream coordinate convention"
expires = 2027-01-01

GeoDebug searches the current directory and its parents for .geodebug.toml. Use --config to select one explicitly.

Profiles are intentionally simple:

  • default — rule defaults
  • strict — warnings become errors
  • exploratory — warnings become notes

Explicit overrides win. Suppressions require a reason and may expire.

Contracts over vibes

A few things GeoDebug refuses to blur:

  • Adapters do not diagnose. They normalize observations into facts.
  • Rules do not perform I/O. They evaluate spatial invariants.
  • UNKNOWN is not PASS. Missing evidence stays missing.
  • Policy does not rewrite truth. It changes severity or visibility, not the rule result.
  • Expensive scans are explicit. --deep means --deep.
  • Automatic repair is conservative. A geometrically valid output is not necessarily a scientifically valid fix.

The canonical report schema is versioned independently at 1.0.0; project config uses schema version 1.

geodebug schema
geodebug schema --kind config

Development

git clone https://github.com/GeoGeekLab/geodebug.git
cd geodebug

python -m venv .venv
source .venv/bin/activate
pip install -e '.[dev,all]'

ruff check .
mypy src/geodebug
pytest

The release gate checks more than unit tests: four-state rule contracts, golden must_not_report cases, metamorphic corrections, clean-corpus silence, cross-platform smoke tests, and installation from a freshly built wheel.

See Architecture, Diagnostic rules, and Releasing for the internals.

Contributing

Contributions should start from a concrete geospatial failure mode or a concrete engineering improvement. New diagnostics must preserve the four-state rule contract and include false-positive coverage where adjacent rules can cascade.

See CONTRIBUTING.md.

Security

Please report vulnerabilities privately through GitHub's security reporting features when available. Do not publish exploit details in a public issue before a fix or mitigation is available.

See SECURITY.md.

License

MIT


Geo to see. Geek to build.

GeoGeekLab

About

Deterministic diagnostics for geospatial data and workflows.

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages