argleton 0.2.0__tar.gz → 0.3.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.
Files changed (208) hide show
  1. {argleton-0.2.0 → argleton-0.3.0}/CITATION.cff +1 -1
  2. {argleton-0.2.0 → argleton-0.3.0}/PKG-INFO +13 -12
  3. {argleton-0.2.0 → argleton-0.3.0}/README.md +12 -11
  4. {argleton-0.2.0 → argleton-0.3.0}/adapters/engine_geopandas.py +28 -0
  5. {argleton-0.2.0 → argleton-0.3.0}/adapters/engine_naive.py +18 -0
  6. {argleton-0.2.0 → argleton-0.3.0}/adapters/mapsmith.py +44 -0
  7. argleton-0.3.0/clean/c023-longitude-first/build.py +44 -0
  8. argleton-0.3.0/clean/c023-longitude-first/probe.toml +43 -0
  9. {argleton-0.2.0 → argleton-0.3.0}/docs/FAMILIES.md +5 -4
  10. {argleton-0.2.0 → argleton-0.3.0}/pyproject.toml +1 -1
  11. argleton-0.3.0/results/2026-08-29-axis-order/adapters-geopandas.json +575 -0
  12. argleton-0.3.0/results/2026-08-29-axis-order/adapters-mapsmith.json +574 -0
  13. argleton-0.3.0/results/2026-08-29-axis-order/adapters-naive.json +574 -0
  14. argleton-0.3.0/results/2026-08-29-axis-order/adapters-rasterio.json +574 -0
  15. argleton-0.3.0/results/2026-08-29-axis-order/adapters-whitebox.json +575 -0
  16. argleton-0.3.0/results/LATEST +1 -0
  17. {argleton-0.2.0 → argleton-0.3.0}/results/README.md +44 -1
  18. {argleton-0.2.0 → argleton-0.3.0}/tests/test_showcase.py +7 -2
  19. argleton-0.3.0/traps/023-axis-order/README.md +130 -0
  20. argleton-0.3.0/traps/023-axis-order/build.py +57 -0
  21. argleton-0.3.0/traps/023-axis-order/probe.toml +110 -0
  22. argleton-0.2.0/results/LATEST +0 -1
  23. {argleton-0.2.0 → argleton-0.3.0}/.gitattributes +0 -0
  24. {argleton-0.2.0 → argleton-0.3.0}/.github/workflows/ci.yml +0 -0
  25. {argleton-0.2.0 → argleton-0.3.0}/.github/workflows/pages.yml +0 -0
  26. {argleton-0.2.0 → argleton-0.3.0}/.gitignore +0 -0
  27. {argleton-0.2.0 → argleton-0.3.0}/LICENSE +0 -0
  28. {argleton-0.2.0 → argleton-0.3.0}/adapters/__init__.py +0 -0
  29. {argleton-0.2.0 → argleton-0.3.0}/adapters/engine_rasterio.py +0 -0
  30. {argleton-0.2.0 → argleton-0.3.0}/adapters/engine_whitebox.py +0 -0
  31. {argleton-0.2.0 → argleton-0.3.0}/adapters/gis_mcp.py +0 -0
  32. {argleton-0.2.0 → argleton-0.3.0}/argleton/__init__.py +0 -0
  33. {argleton-0.2.0 → argleton-0.3.0}/argleton/model.py +0 -0
  34. {argleton-0.2.0 → argleton-0.3.0}/argleton/published.py +0 -0
  35. {argleton-0.2.0 → argleton-0.3.0}/argleton/run.py +0 -0
  36. {argleton-0.2.0 → argleton-0.3.0}/argleton/score.py +0 -0
  37. {argleton-0.2.0 → argleton-0.3.0}/clean/c001-raster-mean/build.py +0 -0
  38. {argleton-0.2.0 → argleton-0.3.0}/clean/c001-raster-mean/probe.toml +0 -0
  39. {argleton-0.2.0 → argleton-0.3.0}/clean/c002-projected-area/build.py +0 -0
  40. {argleton-0.2.0 → argleton-0.3.0}/clean/c002-projected-area/probe.toml +0 -0
  41. {argleton-0.2.0 → argleton-0.3.0}/clean/c003-raster-mean-nodata/build.py +0 -0
  42. {argleton-0.2.0 → argleton-0.3.0}/clean/c003-raster-mean-nodata/probe.toml +0 -0
  43. {argleton-0.2.0 → argleton-0.3.0}/clean/c004-points-in-polygon/build.py +0 -0
  44. {argleton-0.2.0 → argleton-0.3.0}/clean/c004-points-in-polygon/probe.toml +0 -0
  45. {argleton-0.2.0 → argleton-0.3.0}/clean/c005-polygon-area/build.py +0 -0
  46. {argleton-0.2.0 → argleton-0.3.0}/clean/c005-polygon-area/probe.toml +0 -0
  47. {argleton-0.2.0 → argleton-0.3.0}/clean/c006-named-layer/build.py +0 -0
  48. {argleton-0.2.0 → argleton-0.3.0}/clean/c006-named-layer/probe.toml +0 -0
  49. {argleton-0.2.0 → argleton-0.3.0}/clean/c007-distance-in-metres/build.py +0 -0
  50. {argleton-0.2.0 → argleton-0.3.0}/clean/c007-distance-in-metres/probe.toml +0 -0
  51. {argleton-0.2.0 → argleton-0.3.0}/clean/c008-equal-area-crs/build.py +0 -0
  52. {argleton-0.2.0 → argleton-0.3.0}/clean/c008-equal-area-crs/probe.toml +0 -0
  53. {argleton-0.2.0 → argleton-0.3.0}/clean/c009-native-resolution-classes/build.py +0 -0
  54. {argleton-0.2.0 → argleton-0.3.0}/clean/c009-native-resolution-classes/probe.toml +0 -0
  55. {argleton-0.2.0 → argleton-0.3.0}/clean/c010-physical-values/build.py +0 -0
  56. {argleton-0.2.0 → argleton-0.3.0}/clean/c010-physical-values/probe.toml +0 -0
  57. {argleton-0.2.0 → argleton-0.3.0}/clean/c011-solid-parcel/build.py +0 -0
  58. {argleton-0.2.0 → argleton-0.3.0}/clean/c011-solid-parcel/probe.toml +0 -0
  59. {argleton-0.2.0 → argleton-0.3.0}/clean/c012-disjoint-concessions/build.py +0 -0
  60. {argleton-0.2.0 → argleton-0.3.0}/clean/c012-disjoint-concessions/probe.toml +0 -0
  61. {argleton-0.2.0 → argleton-0.3.0}/clean/c013-flat-pipeline/build.py +0 -0
  62. {argleton-0.2.0 → argleton-0.3.0}/clean/c013-flat-pipeline/probe.toml +0 -0
  63. {argleton-0.2.0 → argleton-0.3.0}/clean/c014-convex-parcel/build.py +0 -0
  64. {argleton-0.2.0 → argleton-0.3.0}/clean/c014-convex-parcel/probe.toml +0 -0
  65. {argleton-0.2.0 → argleton-0.3.0}/clean/c015-wells-off-the-seam/build.py +0 -0
  66. {argleton-0.2.0 → argleton-0.3.0}/clean/c015-wells-off-the-seam/probe.toml +0 -0
  67. {argleton-0.2.0 → argleton-0.3.0}/clean/c016-decimal-degrees/build.py +0 -0
  68. {argleton-0.2.0 → argleton-0.3.0}/clean/c016-decimal-degrees/probe.toml +0 -0
  69. {argleton-0.2.0 → argleton-0.3.0}/clean/c017-equal-populations/build.py +0 -0
  70. {argleton-0.2.0 → argleton-0.3.0}/clean/c017-equal-populations/probe.toml +0 -0
  71. {argleton-0.2.0 → argleton-0.3.0}/clean/c018-plain-keys/build.py +0 -0
  72. {argleton-0.2.0 → argleton-0.3.0}/clean/c018-plain-keys/probe.toml +0 -0
  73. {argleton-0.2.0 → argleton-0.3.0}/clean/c019-fully-contained/build.py +0 -0
  74. {argleton-0.2.0 → argleton-0.3.0}/clean/c019-fully-contained/probe.toml +0 -0
  75. {argleton-0.2.0 → argleton-0.3.0}/clean/c020-one-owner-each/build.py +0 -0
  76. {argleton-0.2.0 → argleton-0.3.0}/clean/c020-one-owner-each/probe.toml +0 -0
  77. {argleton-0.2.0 → argleton-0.3.0}/clean/c021-greenwich-variant/build.py +0 -0
  78. {argleton-0.2.0 → argleton-0.3.0}/clean/c021-greenwich-variant/probe.toml +0 -0
  79. {argleton-0.2.0 → argleton-0.3.0}/clean/c022-two-gauges/build.py +0 -0
  80. {argleton-0.2.0 → argleton-0.3.0}/clean/c022-two-gauges/probe.toml +0 -0
  81. {argleton-0.2.0 → argleton-0.3.0}/docs/ADDING-A-TRAP.md +0 -0
  82. {argleton-0.2.0 → argleton-0.3.0}/docs/METHOD.md +0 -0
  83. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-23-first-run/adapters-mapsmith.json +0 -0
  84. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-23-first-run/engine-geopandas.json +0 -0
  85. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-23-first-run/engine-naive.json +0 -0
  86. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-23-first-run/engine-rasterio.json +0 -0
  87. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-23-first-run/engine-whitebox.json +0 -0
  88. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-24-five-families/adapters-mapsmith.json +0 -0
  89. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-24-five-families/engine-geopandas.json +0 -0
  90. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-24-five-families/engine-naive.json +0 -0
  91. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-24-five-families/engine-rasterio.json +0 -0
  92. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-24-five-families/engine-whitebox.json +0 -0
  93. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-25-eight-families/adapters-mapsmith.json +0 -0
  94. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-25-eight-families/engine-geopandas.json +0 -0
  95. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-25-eight-families/engine-naive.json +0 -0
  96. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-25-eight-families/engine-rasterio.json +0 -0
  97. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-25-eight-families/engine-whitebox.json +0 -0
  98. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-25-six-families/adapters-mapsmith.json +0 -0
  99. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-25-six-families/engine-geopandas.json +0 -0
  100. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-25-six-families/engine-naive.json +0 -0
  101. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-25-six-families/engine-rasterio.json +0 -0
  102. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-25-six-families/engine-whitebox.json +0 -0
  103. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-eighteen-families/adapters-geopandas.json +0 -0
  104. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-eighteen-families/adapters-mapsmith.json +0 -0
  105. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-eighteen-families/adapters-naive.json +0 -0
  106. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-eighteen-families/adapters-rasterio.json +0 -0
  107. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-eighteen-families/adapters-whitebox.json +0 -0
  108. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-nine-families/adapters-geopandas.json +0 -0
  109. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-nine-families/adapters-mapsmith.json +0 -0
  110. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-nine-families/adapters-naive.json +0 -0
  111. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-nine-families/adapters-rasterio.json +0 -0
  112. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-nine-families/adapters-whitebox.json +0 -0
  113. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-nineteen-families/adapters-geopandas.json +0 -0
  114. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-nineteen-families/adapters-mapsmith.json +0 -0
  115. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-nineteen-families/adapters-naive.json +0 -0
  116. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-nineteen-families/adapters-rasterio.json +0 -0
  117. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-nineteen-families/adapters-whitebox.json +0 -0
  118. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-ten-families/adapters-geopandas.json +0 -0
  119. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-ten-families/adapters-mapsmith.json +0 -0
  120. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-ten-families/adapters-naive.json +0 -0
  121. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-ten-families/adapters-rasterio.json +0 -0
  122. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-26-ten-families/adapters-whitebox.json +0 -0
  123. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-27-datum-shift-fixed/adapters-geopandas.json +0 -0
  124. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-27-datum-shift-fixed/adapters-mapsmith.json +0 -0
  125. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-27-datum-shift-fixed/adapters-naive.json +0 -0
  126. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-27-datum-shift-fixed/adapters-rasterio.json +0 -0
  127. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-27-datum-shift-fixed/adapters-whitebox.json +0 -0
  128. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-28-thiessen-pairing/adapters-geopandas.json +0 -0
  129. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-28-thiessen-pairing/adapters-mapsmith.json +0 -0
  130. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-28-thiessen-pairing/adapters-naive.json +0 -0
  131. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-28-thiessen-pairing/adapters-rasterio.json +0 -0
  132. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-28-thiessen-pairing/adapters-whitebox.json +0 -0
  133. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-28-timings/adapters-geopandas.json +0 -0
  134. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-28-timings/adapters-mapsmith.json +0 -0
  135. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-28-timings/adapters-naive.json +0 -0
  136. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-28-timings/adapters-rasterio.json +0 -0
  137. {argleton-0.2.0 → argleton-0.3.0}/results/2026-08-28-timings/adapters-whitebox.json +0 -0
  138. {argleton-0.2.0 → argleton-0.3.0}/schema/probe.schema.json +0 -0
  139. {argleton-0.2.0 → argleton-0.3.0}/schema/result.schema.json +0 -0
  140. {argleton-0.2.0 → argleton-0.3.0}/site/build.py +0 -0
  141. {argleton-0.2.0 → argleton-0.3.0}/site/index.template.html +0 -0
  142. {argleton-0.2.0 → argleton-0.3.0}/tests/test_contracts.py +0 -0
  143. {argleton-0.2.0 → argleton-0.3.0}/traps/001-tiff-predictor/README.md +0 -0
  144. {argleton-0.2.0 → argleton-0.3.0}/traps/001-tiff-predictor/build.py +0 -0
  145. {argleton-0.2.0 → argleton-0.3.0}/traps/001-tiff-predictor/probe.toml +0 -0
  146. {argleton-0.2.0 → argleton-0.3.0}/traps/002-feet-as-metres/README.md +0 -0
  147. {argleton-0.2.0 → argleton-0.3.0}/traps/002-feet-as-metres/build.py +0 -0
  148. {argleton-0.2.0 → argleton-0.3.0}/traps/002-feet-as-metres/probe.toml +0 -0
  149. {argleton-0.2.0 → argleton-0.3.0}/traps/003-nodata-in-statistics/README.md +0 -0
  150. {argleton-0.2.0 → argleton-0.3.0}/traps/003-nodata-in-statistics/build.py +0 -0
  151. {argleton-0.2.0 → argleton-0.3.0}/traps/003-nodata-in-statistics/probe.toml +0 -0
  152. {argleton-0.2.0 → argleton-0.3.0}/traps/004-mismatched-crs-join/README.md +0 -0
  153. {argleton-0.2.0 → argleton-0.3.0}/traps/004-mismatched-crs-join/build.py +0 -0
  154. {argleton-0.2.0 → argleton-0.3.0}/traps/004-mismatched-crs-join/probe.toml +0 -0
  155. {argleton-0.2.0 → argleton-0.3.0}/traps/005-bowtie-area/README.md +0 -0
  156. {argleton-0.2.0 → argleton-0.3.0}/traps/005-bowtie-area/build.py +0 -0
  157. {argleton-0.2.0 → argleton-0.3.0}/traps/005-bowtie-area/probe.toml +0 -0
  158. {argleton-0.2.0 → argleton-0.3.0}/traps/006-default-layer/README.md +0 -0
  159. {argleton-0.2.0 → argleton-0.3.0}/traps/006-default-layer/build.py +0 -0
  160. {argleton-0.2.0 → argleton-0.3.0}/traps/006-default-layer/probe.toml +0 -0
  161. {argleton-0.2.0 → argleton-0.3.0}/traps/007-buffer-in-degrees/README.md +0 -0
  162. {argleton-0.2.0 → argleton-0.3.0}/traps/007-buffer-in-degrees/build.py +0 -0
  163. {argleton-0.2.0 → argleton-0.3.0}/traps/007-buffer-in-degrees/probe.toml +0 -0
  164. {argleton-0.2.0 → argleton-0.3.0}/traps/008-web-mercator-area/README.md +0 -0
  165. {argleton-0.2.0 → argleton-0.3.0}/traps/008-web-mercator-area/build.py +0 -0
  166. {argleton-0.2.0 → argleton-0.3.0}/traps/008-web-mercator-area/probe.toml +0 -0
  167. {argleton-0.2.0 → argleton-0.3.0}/traps/009-resampled-classes/README.md +0 -0
  168. {argleton-0.2.0 → argleton-0.3.0}/traps/009-resampled-classes/build.py +0 -0
  169. {argleton-0.2.0 → argleton-0.3.0}/traps/009-resampled-classes/probe.toml +0 -0
  170. {argleton-0.2.0 → argleton-0.3.0}/traps/010-scale-offset/README.md +0 -0
  171. {argleton-0.2.0 → argleton-0.3.0}/traps/010-scale-offset/build.py +0 -0
  172. {argleton-0.2.0 → argleton-0.3.0}/traps/010-scale-offset/probe.toml +0 -0
  173. {argleton-0.2.0 → argleton-0.3.0}/traps/011-polygon-holes/README.md +0 -0
  174. {argleton-0.2.0 → argleton-0.3.0}/traps/011-polygon-holes/build.py +0 -0
  175. {argleton-0.2.0 → argleton-0.3.0}/traps/011-polygon-holes/probe.toml +0 -0
  176. {argleton-0.2.0 → argleton-0.3.0}/traps/012-double-counting/README.md +0 -0
  177. {argleton-0.2.0 → argleton-0.3.0}/traps/012-double-counting/build.py +0 -0
  178. {argleton-0.2.0 → argleton-0.3.0}/traps/012-double-counting/probe.toml +0 -0
  179. {argleton-0.2.0 → argleton-0.3.0}/traps/013-z-dimension/README.md +0 -0
  180. {argleton-0.2.0 → argleton-0.3.0}/traps/013-z-dimension/build.py +0 -0
  181. {argleton-0.2.0 → argleton-0.3.0}/traps/013-z-dimension/probe.toml +0 -0
  182. {argleton-0.2.0 → argleton-0.3.0}/traps/014-centroid-outside/README.md +0 -0
  183. {argleton-0.2.0 → argleton-0.3.0}/traps/014-centroid-outside/build.py +0 -0
  184. {argleton-0.2.0 → argleton-0.3.0}/traps/014-centroid-outside/probe.toml +0 -0
  185. {argleton-0.2.0 → argleton-0.3.0}/traps/015-boundary-semantics/README.md +0 -0
  186. {argleton-0.2.0 → argleton-0.3.0}/traps/015-boundary-semantics/build.py +0 -0
  187. {argleton-0.2.0 → argleton-0.3.0}/traps/015-boundary-semantics/probe.toml +0 -0
  188. {argleton-0.2.0 → argleton-0.3.0}/traps/016-coordinate-parsing/README.md +0 -0
  189. {argleton-0.2.0 → argleton-0.3.0}/traps/016-coordinate-parsing/build.py +0 -0
  190. {argleton-0.2.0 → argleton-0.3.0}/traps/016-coordinate-parsing/probe.toml +0 -0
  191. {argleton-0.2.0 → argleton-0.3.0}/traps/017-aggregation-weighting/README.md +0 -0
  192. {argleton-0.2.0 → argleton-0.3.0}/traps/017-aggregation-weighting/build.py +0 -0
  193. {argleton-0.2.0 → argleton-0.3.0}/traps/017-aggregation-weighting/probe.toml +0 -0
  194. {argleton-0.2.0 → argleton-0.3.0}/traps/018-join-key-typing/README.md +0 -0
  195. {argleton-0.2.0 → argleton-0.3.0}/traps/018-join-key-typing/build.py +0 -0
  196. {argleton-0.2.0 → argleton-0.3.0}/traps/018-join-key-typing/probe.toml +0 -0
  197. {argleton-0.2.0 → argleton-0.3.0}/traps/019-partial-overlap/README.md +0 -0
  198. {argleton-0.2.0 → argleton-0.3.0}/traps/019-partial-overlap/build.py +0 -0
  199. {argleton-0.2.0 → argleton-0.3.0}/traps/019-partial-overlap/probe.toml +0 -0
  200. {argleton-0.2.0 → argleton-0.3.0}/traps/020-join-cardinality/README.md +0 -0
  201. {argleton-0.2.0 → argleton-0.3.0}/traps/020-join-cardinality/build.py +0 -0
  202. {argleton-0.2.0 → argleton-0.3.0}/traps/020-join-cardinality/probe.toml +0 -0
  203. {argleton-0.2.0 → argleton-0.3.0}/traps/021-ballpark-datum/README.md +0 -0
  204. {argleton-0.2.0 → argleton-0.3.0}/traps/021-ballpark-datum/build.py +0 -0
  205. {argleton-0.2.0 → argleton-0.3.0}/traps/021-ballpark-datum/probe.toml +0 -0
  206. {argleton-0.2.0 → argleton-0.3.0}/traps/022-thiessen-pairing/README.md +0 -0
  207. {argleton-0.2.0 → argleton-0.3.0}/traps/022-thiessen-pairing/build.py +0 -0
  208. {argleton-0.2.0 → argleton-0.3.0}/traps/022-thiessen-pairing/probe.toml +0 -0
@@ -7,7 +7,7 @@ authors:
7
7
  repository-code: "https://github.com/argleton/argleton"
8
8
  url: "https://argleton.org"
9
9
  license: Apache-2.0
10
- version: "0.2.0"
10
+ version: "0.3.0"
11
11
  date-released: "2026-08-29"
12
12
  abstract: >-
13
13
  Probes whose right answer is known by construction — derived on paper, never
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: argleton
3
- Version: 0.2.0
3
+ Version: 0.3.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
@@ -67,8 +67,8 @@ machine, so there is nothing to download and nothing to take on trust:
67
67
  pip install "argleton[fixtures]"
68
68
  ```
69
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
70
+ The probes ship with the runner, so that is the whole setup — release 0.3.0 carries the
71
+ 23 traps and 26 families the results below were produced from. When the checkout runs ahead
72
72
  of the release this paragraph says so, because a reader who cannot reproduce the table on
73
73
  this page has been told something untrue.
74
74
 
@@ -109,8 +109,8 @@ every task it was given (completion 1.0) *and* gets this file silently wrong
109
109
  (the 0.5).
110
110
 
111
111
  There is a third adapter, `engine:naive` — read the file, take the statistic,
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
112
+ report it — and it is the most useful one here. It scores **0.9565 / 1.0**: it
113
+ answers every clean probe correctly, falls into twenty-two of the twenty-three traps, and
114
114
  **passes the remaining one**, because rasterio undoes the predictor on its
115
115
  behalf. Careless code is not uniformly wrong. It is correct until the data stops
116
116
  having the shape it usually has, which is what makes the exceptions so hard to
@@ -134,7 +134,7 @@ Side by side, one glance tells you which you are looking at.
134
134
 
135
135
  ## What is covered
136
136
 
137
- Twenty families of twenty-five, and [FAMILIES.md](docs/FAMILIES.md) says which — so a
137
+ Twenty-one families of twenty-six, and [FAMILIES.md](docs/FAMILIES.md) says which — so a
138
138
  number from here can never be read as broader than it is. A low silent-error
139
139
  rate means a system did not fail silently *on these probes*.
140
140
 
@@ -160,19 +160,20 @@ rate means a system did not fail silently *on these probes*.
160
160
  | `aggregation-weighting` | 13.67% instead of 1.38% | averaging rates treats a village as equal to a city |
161
161
  | `tabular-join` | 62000 people instead of 100000 | a CSV reader turns "001" into 1 and four municipalities leave the join |
162
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 |
163
+ | `axis-order` | 16261 m² instead of 14042 | EPSG:4326 declares latitude first and every geometry library expects longitude first; both readings of a corner schedule stay in range |
163
164
 
164
165
  ## Results
165
166
 
166
- Engine tier, twenty families, `spec_commit` pinned — [every run, and what the
167
+ Engine tier, twenty-one families, `spec_commit` pinned — [every run, and what the
167
168
  numbers do not say](results/).
168
169
 
169
170
  | system | silent error rate | completion rate | traps run | not applicable |
170
171
  |---|---|---|---|---|
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 |
172
+ | MapSmith (main) | 0.00 | 1.00 | 23 | 0 |
173
+ | rasterio 1.5.1 (careful composition) | 0.00 | 1.00 | 4 | 38 |
174
+ | GeoPandas 1.1 + Shapely 2 (careful composition) | 0.00 | 1.00 | 9 | 28 |
175
+ | whitebox-workflows 2.0.6 | 0.50 | 1.00 | 2 | 42 |
176
+ | naive composition | 0.9565 | 1.00 | 23 | 0 |
176
177
 
177
178
  The last two columns are not decoration. A rate over two traps and a rate over
178
179
  eight are different claims, and an adapter that could only be asked one question
@@ -31,8 +31,8 @@ machine, so there is nothing to download and nothing to take on trust:
31
31
  pip install "argleton[fixtures]"
32
32
  ```
33
33
 
34
- The probes ship with the runner, so that is the whole setup — release 0.2.0 carries the
35
- 22 traps and 25 families the results below were produced from. When the checkout runs ahead
34
+ The probes ship with the runner, so that is the whole setup — release 0.3.0 carries the
35
+ 23 traps and 26 families the results below were produced from. When the checkout runs ahead
36
36
  of the release this paragraph says so, because a reader who cannot reproduce the table on
37
37
  this page has been told something untrue.
38
38
 
@@ -73,8 +73,8 @@ every task it was given (completion 1.0) *and* gets this file silently wrong
73
73
  (the 0.5).
74
74
 
75
75
  There is a third adapter, `engine:naive` — read the file, take the statistic,
76
- report it — and it is the most useful one here. It scores **0.9545 / 1.0**: it
77
- answers every clean probe correctly, falls into twenty-one of the twenty-two traps, and
76
+ report it — and it is the most useful one here. It scores **0.9565 / 1.0**: it
77
+ answers every clean probe correctly, falls into twenty-two of the twenty-three traps, and
78
78
  **passes the remaining one**, because rasterio undoes the predictor on its
79
79
  behalf. Careless code is not uniformly wrong. It is correct until the data stops
80
80
  having the shape it usually has, which is what makes the exceptions so hard to
@@ -98,7 +98,7 @@ Side by side, one glance tells you which you are looking at.
98
98
 
99
99
  ## What is covered
100
100
 
101
- Twenty families of twenty-five, and [FAMILIES.md](docs/FAMILIES.md) says which — so a
101
+ Twenty-one families of twenty-six, and [FAMILIES.md](docs/FAMILIES.md) says which — so a
102
102
  number from here can never be read as broader than it is. A low silent-error
103
103
  rate means a system did not fail silently *on these probes*.
104
104
 
@@ -124,19 +124,20 @@ rate means a system did not fail silently *on these probes*.
124
124
  | `aggregation-weighting` | 13.67% instead of 1.38% | averaging rates treats a village as equal to a city |
125
125
  | `tabular-join` | 62000 people instead of 100000 | a CSV reader turns "001" into 1 and four municipalities leave the join |
126
126
  | `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 |
127
+ | `axis-order` | 16261 m² instead of 14042 | EPSG:4326 declares latitude first and every geometry library expects longitude first; both readings of a corner schedule stay in range |
127
128
 
128
129
  ## Results
129
130
 
130
- Engine tier, twenty families, `spec_commit` pinned — [every run, and what the
131
+ Engine tier, twenty-one families, `spec_commit` pinned — [every run, and what the
131
132
  numbers do not say](results/).
132
133
 
133
134
  | system | silent error rate | completion rate | traps run | not applicable |
134
135
  |---|---|---|---|---|
135
- | MapSmith (main) | 0.00 | 1.00 | 22 | 0 |
136
- | rasterio 1.5.1 (careful composition) | 0.00 | 1.00 | 4 | 36 |
137
- | GeoPandas 1.1 + Shapely 2 (careful composition) | 0.00 | 1.00 | 8 | 28 |
138
- | whitebox-workflows 2.0.6 | 0.50 | 1.00 | 2 | 40 |
139
- | naive composition | 0.9545 | 1.00 | 22 | 0 |
136
+ | MapSmith (main) | 0.00 | 1.00 | 23 | 0 |
137
+ | rasterio 1.5.1 (careful composition) | 0.00 | 1.00 | 4 | 38 |
138
+ | GeoPandas 1.1 + Shapely 2 (careful composition) | 0.00 | 1.00 | 9 | 28 |
139
+ | whitebox-workflows 2.0.6 | 0.50 | 1.00 | 2 | 42 |
140
+ | naive composition | 0.9565 | 1.00 | 23 | 0 |
140
141
 
141
142
  The last two columns are not decoration. A rate over two traps and a rate over
142
143
  eight are different claims, and an adapter that could only be asked one question
@@ -207,3 +207,31 @@ class Adapter:
207
207
  "assignment is not unique"
208
208
  )
209
209
  return Outcome(answer=float(gauges.loc[nearest, field]))
210
+
211
+ def op_parcel_area_m2(self, probe: Probe, workdir: Path) -> Outcome:
212
+ import csv
213
+
214
+ from pyproj import Geod
215
+ from shapely.geometry import Polygon
216
+
217
+ # The header is the contract. A corner schedule can be written either
218
+ # way round — EPSG:4326 declares latitude first and every geometry
219
+ # library expects longitude first, and both conventions are current —
220
+ # so the column NAMES decide, not their positions.
221
+ with (workdir / probe.arguments[0]).open(encoding="utf-8") as handle:
222
+ rows = list(csv.DictReader(handle))
223
+ names = {name.strip().lower() for name in rows[0]}
224
+ for lon_name, lat_name in (("longitude", "latitude"), ("lon", "lat"), ("x", "y")):
225
+ if {lon_name, lat_name} <= names:
226
+ break
227
+ else:
228
+ return Outcome(
229
+ error="the corner schedule does not name its coordinate columns, "
230
+ "so which one is longitude cannot be established"
231
+ )
232
+ ring = [(float(row[lon_name]), float(row[lat_name])) for row in rows]
233
+ # Geodesic on the ellipsoid the CRS names: no map plane, so no
234
+ # projection distortion enters the answer.
235
+ return Outcome(answer=abs(Geod(ellps="WGS84").geometry_area_perimeter(
236
+ Polygon(ring)
237
+ )[0]))
@@ -238,3 +238,21 @@ class Adapter:
238
238
  if hit.empty:
239
239
  return Outcome(error="no Thiessen cell contains the site")
240
240
  return Outcome(answer=float(hit[field].iloc[0]))
241
+
242
+ def op_parcel_area_m2(self, probe: Probe, workdir: Path) -> Outcome:
243
+ import csv
244
+
245
+ from pyproj import Geod
246
+ from shapely.geometry import Polygon
247
+
248
+ # Read the corner schedule and build the ring: take the two coordinate
249
+ # columns in the order they appear, which is what `Polygon(df.values)`,
250
+ # `np.loadtxt` past the header and every csv.reader loop do.
251
+ #
252
+ # The header names both columns. Nobody asks it which one is x.
253
+ with (workdir / probe.arguments[0]).open(encoding="utf-8") as handle:
254
+ rows = list(csv.reader(handle))
255
+ ring = [(float(row[1]), float(row[2])) for row in rows[1:]]
256
+ return Outcome(answer=abs(Geod(ellps="WGS84").geometry_area_perimeter(
257
+ Polygon(ring)
258
+ )[0]))
@@ -531,3 +531,47 @@ class Adapter:
531
531
  answer=float(values.iloc[0]),
532
532
  warnings=self._warnings(cells) + self._warnings(joined),
533
533
  )
534
+
535
+ def op_parcel_area_m2(self, probe: Probe, workdir: Path) -> Outcome:
536
+ import pandas as pd
537
+ from mapsmith.engines import vector
538
+
539
+ # `parse_coordinates` has no positional path: `latitude_columns` and
540
+ # `longitude_columns` are both required and neither has a default, so
541
+ # the caller cannot hand it two columns and let it guess which is which.
542
+ # That was written for the DMS trap — "the caller says which, because the
543
+ # file cannot" — and it closes this one for the same reason rather than
544
+ # by luck.
545
+ table = workdir / probe.arguments[0]
546
+ columns = {name.strip().lower() for name in pd.read_csv(table, nrows=1).columns}
547
+ for lon_name, lat_name in (("longitude", "latitude"), ("lon", "lat")):
548
+ if {lon_name, lat_name} <= columns:
549
+ break
550
+ else:
551
+ return Outcome(
552
+ error="the corner schedule does not name its coordinate columns"
553
+ )
554
+
555
+ points = workdir / "_argleton_corners.parquet"
556
+ gathered = workdir / "_argleton_gathered.parquet"
557
+ ring = workdir / "_argleton_ring.parquet"
558
+ measured = workdir / "_argleton_area.parquet"
559
+ try:
560
+ vector.parse_coordinates(
561
+ str(table), str(points),
562
+ latitude_columns=lat_name, longitude_columns=lon_name,
563
+ )
564
+ # Dissolve first: `hull` works per feature, so five corner rows
565
+ # would give five hulls of one point each and an area of zero.
566
+ # MapSmith says so rather than returning the zero quietly —
567
+ # "0/5 features have polygonal geometry ... check whether the layer
568
+ # you meant is the polygon one" — which is how this composition got
569
+ # fixed instead of published.
570
+ vector.dissolve(str(points), str(gathered))
571
+ # The corners are convex and given in order, so the hull is the
572
+ # parcel. `hull` states which hull it took.
573
+ vector.hull(str(gathered), str(ring), kind="convex")
574
+ result = vector.measure_area(str(ring), str(measured), method="geodesic")
575
+ except Exception as failure: # noqa: BLE001 - the adapter reports, it does not raise
576
+ return Outcome(error=f"{type(failure).__name__}: {failure}")
577
+ return Outcome(answer=float(result["total_area_m2"]))
@@ -0,0 +1,44 @@
1
+ """The same parcel, the same square, the columns in the machine's order.
2
+
3
+ Identical footprint to 023-axis-order — the same 0.0012 degree square with its
4
+ south-west corner at longitude 23.7300, latitude 37.9800 — so the right answer
5
+ is the same number. The only thing that changed is which column comes first,
6
+ which is the one thing the trap is about.
7
+
8
+ A reader that takes the two columns in the order it finds them is correct here
9
+ and wrong there. A reader that reads the header is correct in both.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import sys
15
+ from pathlib import Path
16
+
17
+ LON0 = 23.7300
18
+ LAT0 = 37.9800
19
+ SIDE = 0.0012
20
+
21
+
22
+ def main(destination: Path) -> int:
23
+ destination.mkdir(parents=True, exist_ok=True)
24
+
25
+ ring = [
26
+ (LON0, LAT0),
27
+ (LON0 + SIDE, LAT0),
28
+ (LON0 + SIDE, LAT0 + SIDE),
29
+ (LON0, LAT0 + SIDE),
30
+ (LON0, LAT0),
31
+ ]
32
+ # Longitude first: the order shapefiles, GeoJSON and every geometry library
33
+ # use, and the order OGC calls CRS84. Just as declared as the other one, and
34
+ # just as common — which is the whole difficulty.
35
+ lines = ["corner,longitude,latitude"]
36
+ lines += [
37
+ f"{index + 1},{lon:.4f},{lat:.4f}" for index, (lon, lat) in enumerate(ring)
38
+ ]
39
+ (destination / "parcel.csv").write_text("\n".join(lines) + "\n", encoding="utf-8")
40
+ return 0
41
+
42
+
43
+ if __name__ == "__main__":
44
+ raise SystemExit(main(Path(sys.argv[1] if len(sys.argv) > 1 else ".")))
@@ -0,0 +1,43 @@
1
+ id = "c023-longitude-first"
2
+ population = "clean"
3
+ family = "axis-order"
4
+ title = "The same corner schedule, longitude first"
5
+ surface = ["engine", "agent"]
6
+
7
+ [task]
8
+ call = "parcel_area_m2(parcel.csv)"
9
+ prompt = """
10
+ parcel.csv is a corner schedule for one land parcel: one row per corner, in
11
+ order, closing the ring. The coordinates are in WGS 84 (EPSG:4326). How large
12
+ is the parcel on the ground, in square metres? Answer with the number."""
13
+
14
+ [truth]
15
+ kind = "scalar"
16
+ value = 14047.0
17
+ tolerance = 8.0
18
+ derivation = """
19
+ The same parcel as 023-axis-order and therefore the same number: an axis-aligned
20
+ square of 0.0012 deg with its south-west corner at longitude 23.7300, latitude
21
+ 37.9800, whose ellipsoidal area is 14042.346 m2 by the zone integral, 14042.346
22
+ by pyproj's geodesic area and 14051.010 in the UTM 34N plane. The tolerance of 8
23
+ around 14047 admits all three.
24
+
25
+ What changed is the column order in the file: longitude first, as the header
26
+ says. Reading the two columns in the order they appear is correct here."""
27
+
28
+ [provenance]
29
+ source = """
30
+ Clean twin of 023-axis-order: the same question, the same footprint, the same
31
+ five rows, the same header line naming both columns. One thing differs, and it
32
+ is the thing under test — which of the two declared conventions the file uses.
33
+
34
+ Without this twin a silent-error rate on the family could not be told apart from
35
+ a system that cannot read a corner schedule at all. A system that answers this
36
+ and fails 023 mishandles axis order; one that fails both cannot do the task, and
37
+ that is a different and lesser finding."""
38
+ found_by = "mapsmith"
39
+ date = "2026-08-29"
40
+
41
+ [provenance.engine_versions]
42
+ pyproj = "3.7.2/PROJ 9.5.1"
43
+ shapely = "2.1.2"
@@ -1,8 +1,8 @@
1
1
  # Families, and what is actually covered
2
2
 
3
- Twenty-four families are on the list — twelve planned at the start, twelve added
3
+ Twenty-six families are on the list — twelve planned at the start, fourteen added
4
4
  from reproductions and from a survey of what the archives and the libraries
5
- themselves warn about. **Twenty are implemented.** This page exists so that
5
+ themselves warn about. **Twenty-one are implemented.** This page exists so that
6
6
  a number from Argleton can never be read as broader than it is: a low
7
7
  silent-error rate means a system did not fail silently *on these probes*, and
8
8
  this is the list of what that sentence covers.
@@ -18,6 +18,7 @@ cannot read as ten independent findings.
18
18
  | 3 | `linear-units` | [002](../traps/002-feet-as-metres/) + [c002](../clean/c002-projected-area/) | 100 ha instead of 9.29 ha | Both are ordinary parcels; they differ by 3.28², a factor nothing downstream questions |
19
19
  | 4 | `mismatched-crs` | [004](../traps/004-mismatched-crs-join/) + [c004](../clean/c004-points-in-polygon/) | 0 points in the zone instead of 12 | An empty spatial result is a finding, not an error — "no wells inside the zone" reads as good news, and nothing downstream questions an empty join |
20
20
  | 25 | `positional-pairing` | [022](../traps/022-thiessen-pairing/) + [c022](../clean/c022-two-gauges/) | 554 mm of rainfall instead of 268 | The cells are all valid, they tile the extent, the count is right and the map is a Thiessen diagram — only the pairing between a cell and the row it carries is wrong, and the set of cells is identical either way, so nothing about the geometry can show it |
21
+ | 26 | `axis-order` | [023](../traps/023-axis-order/) + [c023](../clean/c023-longitude-first/) | 16261 m² instead of 14042 | EPSG:4326 declares latitude first and every geometry library expects longitude first — both conventions are current, both are declared, and a corner schedule read in the order it is written puts the parcel 14 degrees away without leaving the valid range for either coordinate |
21
22
  | 24 | `datum-ballpark` | [021](../traps/021-ballpark-datum/) + [c021](../clean/c021-greenwich-variant/) | latitude 45.5 instead of 45.500669074, which is 74 m | The longitude is right, the output CRS is right, and the transformation the library chose reports its accuracy as -1 only if you ask after the fact |
22
23
  | 6 | `nodata` | [003](../traps/003-nodata-in-statistics/) + [c003](../clean/c003-raster-mean-nodata/) | mean 945.005 instead of 1000.0 | 5.5% out — too small to question, too large to ignore in a volume or a flood level |
23
24
  | 7 | `invalid-geometry` | [005](../traps/005-bowtie-area/) + [c005](../clean/c005-polygon-area/) | 2400 m² instead of 5100 m² | The signed-shoelace artifact of a self-crossing ring: no exception, no warning, and both numbers are ordinary parcels |
@@ -93,8 +94,8 @@ See [ADDING-A-TRAP.md](ADDING-A-TRAP.md).
93
94
 
94
95
  ## What this list does not claim
95
96
 
96
- That these twenty-five are the complete set. They are the families we can currently
97
- argue for, each with a source. A twenty-sixth that meets the four conditions
97
+ That these twenty-six are the complete set. They are the families we can currently
98
+ argue for, each with a source. A twenty-seventh that meets the four conditions
98
99
  belongs here, and the fastest way to improve this suite is to bring one — the
99
100
  same survey that produced the last nine has more candidates in it than this
100
101
  list has entries, and being able to say which ones failed the conditions is
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "argleton"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "Probes whose right answer is known by construction, and whose wrong answer looks fine"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11" # tomllib, so the runner needs nothing installed