argleton 0.1.0__tar.gz → 0.2.0__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.
- {argleton-0.1.0 → argleton-0.2.0}/.github/workflows/ci.yml +81 -81
- {argleton-0.1.0 → argleton-0.2.0}/CITATION.cff +17 -15
- {argleton-0.1.0 → argleton-0.2.0}/PKG-INFO +25 -13
- {argleton-0.1.0 → argleton-0.2.0}/README.md +251 -239
- {argleton-0.1.0 → argleton-0.2.0}/adapters/engine_geopandas.py +209 -176
- {argleton-0.1.0 → argleton-0.2.0}/adapters/engine_naive.py +20 -0
- {argleton-0.1.0 → argleton-0.2.0}/adapters/gis_mcp.py +28 -0
- {argleton-0.1.0 → argleton-0.2.0}/adapters/mapsmith.py +37 -0
- {argleton-0.1.0 → argleton-0.2.0}/argleton/model.py +213 -202
- {argleton-0.1.0 → argleton-0.2.0}/argleton/run.py +198 -170
- {argleton-0.1.0 → argleton-0.2.0}/argleton/score.py +211 -150
- argleton-0.2.0/clean/c022-two-gauges/build.py +48 -0
- argleton-0.2.0/clean/c022-two-gauges/probe.toml +41 -0
- {argleton-0.1.0 → argleton-0.2.0}/docs/FAMILIES.md +4 -3
- {argleton-0.1.0 → argleton-0.2.0}/docs/METHOD.md +209 -166
- {argleton-0.1.0 → argleton-0.2.0}/pyproject.toml +68 -68
- argleton-0.2.0/results/2026-08-28-thiessen-pairing/adapters-geopandas.json +452 -0
- argleton-0.2.0/results/2026-08-28-thiessen-pairing/adapters-mapsmith.json +451 -0
- argleton-0.2.0/results/2026-08-28-thiessen-pairing/adapters-naive.json +451 -0
- argleton-0.2.0/results/2026-08-28-thiessen-pairing/adapters-rasterio.json +451 -0
- argleton-0.2.0/results/2026-08-28-thiessen-pairing/adapters-whitebox.json +452 -0
- argleton-0.2.0/results/2026-08-28-timings/adapters-geopandas.json +551 -0
- argleton-0.2.0/results/2026-08-28-timings/adapters-mapsmith.json +550 -0
- argleton-0.2.0/results/2026-08-28-timings/adapters-naive.json +550 -0
- argleton-0.2.0/results/2026-08-28-timings/adapters-rasterio.json +550 -0
- argleton-0.2.0/results/2026-08-28-timings/adapters-whitebox.json +551 -0
- argleton-0.2.0/results/LATEST +1 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/README.md +115 -4
- argleton-0.2.0/schema/result.schema.json +244 -0
- {argleton-0.1.0 → argleton-0.2.0}/site/build.py +246 -221
- {argleton-0.1.0 → argleton-0.2.0}/site/index.template.html +366 -342
- {argleton-0.1.0 → argleton-0.2.0}/tests/test_showcase.py +453 -350
- argleton-0.2.0/traps/022-thiessen-pairing/README.md +114 -0
- argleton-0.2.0/traps/022-thiessen-pairing/build.py +67 -0
- argleton-0.2.0/traps/022-thiessen-pairing/probe.toml +94 -0
- argleton-0.1.0/results/LATEST +0 -1
- argleton-0.1.0/schema/result.schema.json +0 -103
- {argleton-0.1.0 → argleton-0.2.0}/.gitattributes +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/.github/workflows/pages.yml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/.gitignore +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/LICENSE +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/adapters/__init__.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/adapters/engine_rasterio.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/adapters/engine_whitebox.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/argleton/__init__.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/argleton/published.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c001-raster-mean/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c001-raster-mean/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c002-projected-area/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c002-projected-area/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c003-raster-mean-nodata/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c003-raster-mean-nodata/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c004-points-in-polygon/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c004-points-in-polygon/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c005-polygon-area/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c005-polygon-area/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c006-named-layer/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c006-named-layer/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c007-distance-in-metres/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c007-distance-in-metres/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c008-equal-area-crs/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c008-equal-area-crs/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c009-native-resolution-classes/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c009-native-resolution-classes/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c010-physical-values/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c010-physical-values/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c011-solid-parcel/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c011-solid-parcel/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c012-disjoint-concessions/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c012-disjoint-concessions/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c013-flat-pipeline/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c013-flat-pipeline/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c014-convex-parcel/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c014-convex-parcel/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c015-wells-off-the-seam/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c015-wells-off-the-seam/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c016-decimal-degrees/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c016-decimal-degrees/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c017-equal-populations/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c017-equal-populations/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c018-plain-keys/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c018-plain-keys/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c019-fully-contained/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c019-fully-contained/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c020-one-owner-each/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c020-one-owner-each/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c021-greenwich-variant/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/clean/c021-greenwich-variant/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/docs/ADDING-A-TRAP.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-23-first-run/adapters-mapsmith.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-23-first-run/engine-geopandas.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-23-first-run/engine-naive.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-23-first-run/engine-rasterio.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-23-first-run/engine-whitebox.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-24-five-families/adapters-mapsmith.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-24-five-families/engine-geopandas.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-24-five-families/engine-naive.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-24-five-families/engine-rasterio.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-24-five-families/engine-whitebox.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-25-eight-families/adapters-mapsmith.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-25-eight-families/engine-geopandas.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-25-eight-families/engine-naive.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-25-eight-families/engine-rasterio.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-25-eight-families/engine-whitebox.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-25-six-families/adapters-mapsmith.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-25-six-families/engine-geopandas.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-25-six-families/engine-naive.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-25-six-families/engine-rasterio.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-25-six-families/engine-whitebox.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-eighteen-families/adapters-geopandas.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-eighteen-families/adapters-mapsmith.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-eighteen-families/adapters-naive.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-eighteen-families/adapters-rasterio.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-eighteen-families/adapters-whitebox.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-nine-families/adapters-geopandas.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-nine-families/adapters-mapsmith.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-nine-families/adapters-naive.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-nine-families/adapters-rasterio.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-nine-families/adapters-whitebox.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-nineteen-families/adapters-geopandas.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-nineteen-families/adapters-mapsmith.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-nineteen-families/adapters-naive.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-nineteen-families/adapters-rasterio.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-nineteen-families/adapters-whitebox.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-ten-families/adapters-geopandas.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-ten-families/adapters-mapsmith.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-ten-families/adapters-naive.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-ten-families/adapters-rasterio.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-26-ten-families/adapters-whitebox.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-27-datum-shift-fixed/adapters-geopandas.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-27-datum-shift-fixed/adapters-mapsmith.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-27-datum-shift-fixed/adapters-naive.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-27-datum-shift-fixed/adapters-rasterio.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/results/2026-08-27-datum-shift-fixed/adapters-whitebox.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/schema/probe.schema.json +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/tests/test_contracts.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/001-tiff-predictor/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/001-tiff-predictor/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/001-tiff-predictor/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/002-feet-as-metres/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/002-feet-as-metres/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/002-feet-as-metres/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/003-nodata-in-statistics/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/003-nodata-in-statistics/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/003-nodata-in-statistics/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/004-mismatched-crs-join/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/004-mismatched-crs-join/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/004-mismatched-crs-join/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/005-bowtie-area/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/005-bowtie-area/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/005-bowtie-area/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/006-default-layer/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/006-default-layer/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/006-default-layer/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/007-buffer-in-degrees/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/007-buffer-in-degrees/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/007-buffer-in-degrees/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/008-web-mercator-area/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/008-web-mercator-area/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/008-web-mercator-area/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/009-resampled-classes/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/009-resampled-classes/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/009-resampled-classes/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/010-scale-offset/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/010-scale-offset/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/010-scale-offset/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/011-polygon-holes/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/011-polygon-holes/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/011-polygon-holes/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/012-double-counting/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/012-double-counting/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/012-double-counting/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/013-z-dimension/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/013-z-dimension/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/013-z-dimension/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/014-centroid-outside/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/014-centroid-outside/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/014-centroid-outside/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/015-boundary-semantics/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/015-boundary-semantics/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/015-boundary-semantics/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/016-coordinate-parsing/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/016-coordinate-parsing/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/016-coordinate-parsing/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/017-aggregation-weighting/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/017-aggregation-weighting/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/017-aggregation-weighting/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/018-join-key-typing/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/018-join-key-typing/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/018-join-key-typing/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/019-partial-overlap/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/019-partial-overlap/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/019-partial-overlap/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/020-join-cardinality/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/020-join-cardinality/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/020-join-cardinality/probe.toml +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/021-ballpark-datum/README.md +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/021-ballpark-datum/build.py +0 -0
- {argleton-0.1.0 → argleton-0.2.0}/traps/021-ballpark-datum/probe.toml +0 -0
|
@@ -1,81 +1,81 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main]
|
|
6
|
-
pull_request:
|
|
7
|
-
|
|
8
|
-
permissions:
|
|
9
|
-
contents: read
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
suite:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
strategy:
|
|
15
|
-
matrix:
|
|
16
|
-
python: ["3.11", "3.13"]
|
|
17
|
-
steps:
|
|
18
|
-
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
19
|
-
- uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
|
20
|
-
with:
|
|
21
|
-
python-version: ${{ matrix.python }}
|
|
22
|
-
- run: pip install -e .[fixtures,whitebox,geopandas,dev]
|
|
23
|
-
- run: pip install ruff==0.16.3
|
|
24
|
-
- run: ruff check .
|
|
25
|
-
- run: pytest -q
|
|
26
|
-
# The engine tier is deterministic and free, so it runs on every commit.
|
|
27
|
-
# rasterio must stay at zero silent errors; whitebox is expected to fail
|
|
28
|
-
# trap 001 until upstream fixes it, which is why the run is not gated on
|
|
29
|
-
# the rate — a red build for a defect in someone else's library would
|
|
30
|
-
# train us to ignore the build.
|
|
31
|
-
- run: argleton --adapter engine:rasterio --out /tmp/rasterio.json
|
|
32
|
-
- run: argleton --adapter engine:geopandas --out /tmp/geopandas.json
|
|
33
|
-
- run: argleton --adapter engine:whitebox --out /tmp/whitebox.json
|
|
34
|
-
- run: argleton --adapter engine:naive --out /tmp/naive.json
|
|
35
|
-
# The careful adapters must stay at zero. "Careful" is not a compliment
|
|
36
|
-
# about the library: `engine:rasterio` and `engine:geopandas` compose those
|
|
37
|
-
# libraries the way a caller who knows them does — unit read from the CRS,
|
|
38
|
-
# geographic CRS refused for a planar area, invalid ring repaired and the
|
|
39
|
-
# repair disclosed, a ballpark transformation detected. `engine:naive` is
|
|
40
|
-
# the same libraries composed the way almost everyone writes first, and the
|
|
41
|
-
# gap between the two rows is what this suite is for.
|
|
42
|
-
#
|
|
43
|
-
# The other two are expected to fail their traps — one because of a defect
|
|
44
|
-
# in someone else's library, one because it is the careless composition on
|
|
45
|
-
# purpose — so the build is not gated on them. A red build for a known
|
|
46
|
-
# upstream bug would train us to ignore the build, which costs more than
|
|
47
|
-
# the signal is worth.
|
|
48
|
-
#
|
|
49
|
-
# This gate went red on 2026-08-26 for a good reason: `engine:geopandas`
|
|
50
|
-
# had one operation doing the ordinary thing while its other nine did the
|
|
51
|
-
# careful thing, so it was no longer the adapter this gate describes. The
|
|
52
|
-
# answer was to make the adapter consistent again AND to fix the label on
|
|
53
|
-
# the published table, which is what had been misleading.
|
|
54
|
-
- name: the careful adapters must have no silent errors
|
|
55
|
-
run: |
|
|
56
|
-
python - <<'PY'
|
|
57
|
-
import json, sys
|
|
58
|
-
bad = []
|
|
59
|
-
for name in ("rasterio", "geopandas"):
|
|
60
|
-
r = json.load(open(f"/tmp/{name}.json"))
|
|
61
|
-
print(name, r["silent_error_rate"], r["completion_rate"])
|
|
62
|
-
if r["silent_error_rate"] != 0.0 or r["completion_rate"] != 1.0:
|
|
63
|
-
bad.append(name)
|
|
64
|
-
sys.exit(1 if bad else 0)
|
|
65
|
-
PY
|
|
66
|
-
# And the ones that are supposed to fail must still fail: a trap that
|
|
67
|
-
# stops catching its own naive adapter has quietly stopped measuring.
|
|
68
|
-
- name: the naive adapter must still fall into its trap
|
|
69
|
-
run: |
|
|
70
|
-
python - <<'PY'
|
|
71
|
-
import json, sys
|
|
72
|
-
r = json.load(open("/tmp/naive.json"))
|
|
73
|
-
print(r["silent_error_rate"], r["completion_rate"])
|
|
74
|
-
# Not 1.0: the careless composition is correct on trap 001, because
|
|
75
|
-
# rasterio undoes the predictor for it. Pinning the exact rate is the
|
|
76
|
-
# point — a trap that stops catching its own naive adapter, or one
|
|
77
|
-
# that starts catching a case it should not, has changed what it
|
|
78
|
-
# measures, and that must be a decision rather than a surprise.
|
|
79
|
-
# 0.
|
|
80
|
-
sys.exit(0 if (r["silent_error_rate"], r["completion_rate"]) == (0.
|
|
81
|
-
PY
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
suite:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
strategy:
|
|
15
|
+
matrix:
|
|
16
|
+
python: ["3.11", "3.13"]
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
19
|
+
- uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
|
20
|
+
with:
|
|
21
|
+
python-version: ${{ matrix.python }}
|
|
22
|
+
- run: pip install -e .[fixtures,whitebox,geopandas,dev]
|
|
23
|
+
- run: pip install ruff==0.16.3
|
|
24
|
+
- run: ruff check .
|
|
25
|
+
- run: pytest -q
|
|
26
|
+
# The engine tier is deterministic and free, so it runs on every commit.
|
|
27
|
+
# rasterio must stay at zero silent errors; whitebox is expected to fail
|
|
28
|
+
# trap 001 until upstream fixes it, which is why the run is not gated on
|
|
29
|
+
# the rate — a red build for a defect in someone else's library would
|
|
30
|
+
# train us to ignore the build.
|
|
31
|
+
- run: argleton --adapter engine:rasterio --out /tmp/rasterio.json
|
|
32
|
+
- run: argleton --adapter engine:geopandas --out /tmp/geopandas.json
|
|
33
|
+
- run: argleton --adapter engine:whitebox --out /tmp/whitebox.json
|
|
34
|
+
- run: argleton --adapter engine:naive --out /tmp/naive.json
|
|
35
|
+
# The careful adapters must stay at zero. "Careful" is not a compliment
|
|
36
|
+
# about the library: `engine:rasterio` and `engine:geopandas` compose those
|
|
37
|
+
# libraries the way a caller who knows them does — unit read from the CRS,
|
|
38
|
+
# geographic CRS refused for a planar area, invalid ring repaired and the
|
|
39
|
+
# repair disclosed, a ballpark transformation detected. `engine:naive` is
|
|
40
|
+
# the same libraries composed the way almost everyone writes first, and the
|
|
41
|
+
# gap between the two rows is what this suite is for.
|
|
42
|
+
#
|
|
43
|
+
# The other two are expected to fail their traps — one because of a defect
|
|
44
|
+
# in someone else's library, one because it is the careless composition on
|
|
45
|
+
# purpose — so the build is not gated on them. A red build for a known
|
|
46
|
+
# upstream bug would train us to ignore the build, which costs more than
|
|
47
|
+
# the signal is worth.
|
|
48
|
+
#
|
|
49
|
+
# This gate went red on 2026-08-26 for a good reason: `engine:geopandas`
|
|
50
|
+
# had one operation doing the ordinary thing while its other nine did the
|
|
51
|
+
# careful thing, so it was no longer the adapter this gate describes. The
|
|
52
|
+
# answer was to make the adapter consistent again AND to fix the label on
|
|
53
|
+
# the published table, which is what had been misleading.
|
|
54
|
+
- name: the careful adapters must have no silent errors
|
|
55
|
+
run: |
|
|
56
|
+
python - <<'PY'
|
|
57
|
+
import json, sys
|
|
58
|
+
bad = []
|
|
59
|
+
for name in ("rasterio", "geopandas"):
|
|
60
|
+
r = json.load(open(f"/tmp/{name}.json"))
|
|
61
|
+
print(name, r["silent_error_rate"], r["completion_rate"])
|
|
62
|
+
if r["silent_error_rate"] != 0.0 or r["completion_rate"] != 1.0:
|
|
63
|
+
bad.append(name)
|
|
64
|
+
sys.exit(1 if bad else 0)
|
|
65
|
+
PY
|
|
66
|
+
# And the ones that are supposed to fail must still fail: a trap that
|
|
67
|
+
# stops catching its own naive adapter has quietly stopped measuring.
|
|
68
|
+
- name: the naive adapter must still fall into its trap
|
|
69
|
+
run: |
|
|
70
|
+
python - <<'PY'
|
|
71
|
+
import json, sys
|
|
72
|
+
r = json.load(open("/tmp/naive.json"))
|
|
73
|
+
print(r["silent_error_rate"], r["completion_rate"])
|
|
74
|
+
# Not 1.0: the careless composition is correct on trap 001, because
|
|
75
|
+
# rasterio undoes the predictor for it. Pinning the exact rate is the
|
|
76
|
+
# point — a trap that stops catching its own naive adapter, or one
|
|
77
|
+
# that starts catching a case it should not, has changed what it
|
|
78
|
+
# measures, and that must be a decision rather than a surprise.
|
|
79
|
+
# 0.9545 = traps 002 through 022 caught, 001 passed, out of 22.
|
|
80
|
+
sys.exit(0 if (r["silent_error_rate"], r["completion_rate"]) == (0.9545, 1.0) else 1)
|
|
81
|
+
PY
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
cff-version: 1.2.0
|
|
2
|
-
message: "If you use Argleton in your work, please cite it as below."
|
|
3
|
-
title: "Argleton: a correctness suite for geospatial systems"
|
|
4
|
-
type: software
|
|
5
|
-
authors:
|
|
6
|
-
- name: "The Argleton project"
|
|
7
|
-
repository-code: "https://github.com/argleton/argleton"
|
|
8
|
-
url: "https://argleton.org"
|
|
9
|
-
license: Apache-2.0
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use Argleton in your work, please cite it as below."
|
|
3
|
+
title: "Argleton: a correctness suite for geospatial systems"
|
|
4
|
+
type: software
|
|
5
|
+
authors:
|
|
6
|
+
- name: "The Argleton project"
|
|
7
|
+
repository-code: "https://github.com/argleton/argleton"
|
|
8
|
+
url: "https://argleton.org"
|
|
9
|
+
license: Apache-2.0
|
|
10
|
+
version: "0.2.0"
|
|
11
|
+
date-released: "2026-08-29"
|
|
12
|
+
abstract: >-
|
|
13
|
+
Probes whose right answer is known by construction — derived on paper, never
|
|
14
|
+
measured from a reference implementation — and whose typical wrong answer
|
|
15
|
+
looks fine. Argleton measures the silent-error rate of geospatial systems
|
|
16
|
+
alongside their completion rate on defect-free twins, so that a score cannot
|
|
17
|
+
be gamed by refusing to answer.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: argleton
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Probes whose right answer is known by construction, and whose wrong answer looks fine
|
|
5
5
|
Project-URL: Source, https://github.com/argleton/argleton
|
|
6
6
|
Author: Argleton contributors
|
|
@@ -60,9 +60,20 @@ ordinary elevations. The raster still renders as terrain, hillshade still looks
|
|
|
60
60
|
like hillshade, flow accumulation still flows downhill. Nothing anywhere says
|
|
61
61
|
anything is wrong.
|
|
62
62
|
|
|
63
|
-
Seeing it needs
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
Seeing it needs one install — every fixture is rebuilt deterministically on your
|
|
64
|
+
machine, so there is nothing to download and nothing to take on trust:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
pip install "argleton[fixtures]"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The probes ship with the runner, so that is the whole setup — release 0.2.0 carries the
|
|
71
|
+
22 traps and 25 families the results below were produced from. When the checkout runs ahead
|
|
72
|
+
of the release this paragraph says so, because a reader who cannot reproduce the table on
|
|
73
|
+
this page has been told something untrue.
|
|
74
|
+
|
|
75
|
+
To read the probes, change them, or add one, take the checkout instead — the probes are the point of the
|
|
76
|
+
repository and `probe.toml` is meant to be read:
|
|
66
77
|
|
|
67
78
|
```
|
|
68
79
|
git clone https://github.com/argleton/argleton
|
|
@@ -98,8 +109,8 @@ every task it was given (completion 1.0) *and* gets this file silently wrong
|
|
|
98
109
|
(the 0.5).
|
|
99
110
|
|
|
100
111
|
There is a third adapter, `engine:naive` — read the file, take the statistic,
|
|
101
|
-
report it — and it is the most useful one here. It scores **0.
|
|
102
|
-
answers every clean probe correctly, falls into twenty of the twenty-
|
|
112
|
+
report it — and it is the most useful one here. It scores **0.9545 / 1.0**: it
|
|
113
|
+
answers every clean probe correctly, falls into twenty-one of the twenty-two traps, and
|
|
103
114
|
**passes the remaining one**, because rasterio undoes the predictor on its
|
|
104
115
|
behalf. Careless code is not uniformly wrong. It is correct until the data stops
|
|
105
116
|
having the shape it usually has, which is what makes the exceptions so hard to
|
|
@@ -123,7 +134,7 @@ Side by side, one glance tells you which you are looking at.
|
|
|
123
134
|
|
|
124
135
|
## What is covered
|
|
125
136
|
|
|
126
|
-
|
|
137
|
+
Twenty families of twenty-five, and [FAMILIES.md](docs/FAMILIES.md) says which — so a
|
|
127
138
|
number from here can never be read as broader than it is. A low silent-error
|
|
128
139
|
rate means a system did not fail silently *on these probes*.
|
|
129
140
|
|
|
@@ -148,19 +159,20 @@ rate means a system did not fail silently *on these probes*.
|
|
|
148
159
|
| `coordinate-parsing` | 41.5324 instead of 41.89 | both are latitudes in central Italy, 40 km apart |
|
|
149
160
|
| `aggregation-weighting` | 13.67% instead of 1.38% | averaging rates treats a village as equal to a city |
|
|
150
161
|
| `tabular-join` | 62000 people instead of 100000 | a CSV reader turns "001" into 1 and four municipalities leave the join |
|
|
162
|
+
| `positional-pairing` | 554 mm of rainfall instead of 268 | the Thiessen cells are all valid and tile the extent; only the row each one carries is wrong |
|
|
151
163
|
|
|
152
164
|
## Results
|
|
153
165
|
|
|
154
|
-
Engine tier,
|
|
166
|
+
Engine tier, twenty families, `spec_commit` pinned — [every run, and what the
|
|
155
167
|
numbers do not say](results/).
|
|
156
168
|
|
|
157
169
|
| system | silent error rate | completion rate | traps run | not applicable |
|
|
158
170
|
|---|---|---|---|---|
|
|
159
|
-
| MapSmith (main) | 0.00 | 1.00 |
|
|
160
|
-
| rasterio 1.5.1 (careful composition) | 0.00 | 1.00 | 4 |
|
|
161
|
-
| GeoPandas 1.1 + Shapely 2 (careful composition) | 0.00 | 1.00 |
|
|
162
|
-
| whitebox-workflows 2.0.6 | 0.50 | 1.00 | 2 |
|
|
163
|
-
| naive composition | 0.
|
|
171
|
+
| MapSmith (main) | 0.00 | 1.00 | 22 | 0 |
|
|
172
|
+
| rasterio 1.5.1 (careful composition) | 0.00 | 1.00 | 4 | 36 |
|
|
173
|
+
| GeoPandas 1.1 + Shapely 2 (careful composition) | 0.00 | 1.00 | 8 | 28 |
|
|
174
|
+
| whitebox-workflows 2.0.6 | 0.50 | 1.00 | 2 | 40 |
|
|
175
|
+
| naive composition | 0.9545 | 1.00 | 22 | 0 |
|
|
164
176
|
|
|
165
177
|
The last two columns are not decoration. A rate over two traps and a rate over
|
|
166
178
|
eight are different claims, and an adapter that could only be asked one question
|