argleton 0.4.0__tar.gz → 0.6.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 (311) hide show
  1. {argleton-0.4.0 → argleton-0.6.0}/.github/workflows/ci.yml +16 -8
  2. {argleton-0.4.0 → argleton-0.6.0}/.zenodo.json +1 -1
  3. argleton-0.6.0/CHANGELOG.md +139 -0
  4. {argleton-0.4.0 → argleton-0.6.0}/CITATION.cff +7 -2
  5. {argleton-0.4.0 → argleton-0.6.0}/PKG-INFO +97 -44
  6. {argleton-0.4.0 → argleton-0.6.0}/README.md +96 -43
  7. {argleton-0.4.0 → argleton-0.6.0}/adapters/engine_geopandas.py +27 -0
  8. {argleton-0.4.0 → argleton-0.6.0}/adapters/engine_naive.py +10 -0
  9. argleton-0.6.0/adapters/engine_qgis.py +181 -0
  10. {argleton-0.4.0 → argleton-0.6.0}/adapters/engine_rasterio.py +7 -11
  11. argleton-0.6.0/adapters/gis_mcp.py +541 -0
  12. {argleton-0.4.0 → argleton-0.6.0}/adapters/mapsmith.py +9 -0
  13. argleton-0.6.0/adapters/qgis_agent_mcp.py +241 -0
  14. argleton-0.6.0/adapters/qgis_chains.py +631 -0
  15. argleton-0.6.0/adapters/qgis_mcp_plugin.py +151 -0
  16. argleton-0.6.0/argleton/__init__.py +38 -0
  17. {argleton-0.4.0 → argleton-0.6.0}/argleton/model.py +2 -2
  18. {argleton-0.4.0 → argleton-0.6.0}/argleton/run.py +84 -19
  19. {argleton-0.4.0 → argleton-0.6.0}/clean/c024-pixel-is-area/build.py +6 -4
  20. {argleton-0.4.0 → argleton-0.6.0}/clean/c024-pixel-is-area/probe.toml +17 -15
  21. argleton-0.6.0/clean/c031-hole-wound-as-hole/README.md +16 -0
  22. argleton-0.6.0/clean/c031-hole-wound-as-hole/build.py +54 -0
  23. argleton-0.6.0/clean/c031-hole-wound-as-hole/probe.toml +44 -0
  24. {argleton-0.4.0 → argleton-0.6.0}/docs/FAMILIES.md +134 -142
  25. {argleton-0.4.0 → argleton-0.6.0}/docs/METHOD.md +21 -0
  26. {argleton-0.4.0 → argleton-0.6.0}/pyproject.toml +1 -1
  27. argleton-0.6.0/results/2026-09-02-ring-role/adapters-geopandas.json +767 -0
  28. argleton-0.6.0/results/2026-09-02-ring-role/adapters-mapsmith.json +767 -0
  29. argleton-0.6.0/results/2026-09-02-ring-role/adapters-naive.json +766 -0
  30. argleton-0.6.0/results/2026-09-02-ring-role/adapters-rasterio.json +767 -0
  31. argleton-0.6.0/results/2026-09-02-ring-role/adapters-whitebox.json +767 -0
  32. argleton-0.6.0/results/2026-09-02-thirty-traps/adapters-geopandas.json +743 -0
  33. argleton-0.6.0/results/2026-09-02-thirty-traps/adapters-mapsmith.json +743 -0
  34. argleton-0.6.0/results/2026-09-02-thirty-traps/adapters-naive.json +742 -0
  35. argleton-0.6.0/results/2026-09-02-thirty-traps/adapters-rasterio.json +743 -0
  36. argleton-0.6.0/results/2026-09-02-thirty-traps/adapters-whitebox.json +743 -0
  37. argleton-0.6.0/results/2026-09-10-gis-mcp/adapters-geopandas.json +767 -0
  38. argleton-0.6.0/results/2026-09-10-gis-mcp/adapters-gis-mcp.json +767 -0
  39. argleton-0.6.0/results/2026-09-10-gis-mcp/adapters-mapsmith.json +767 -0
  40. argleton-0.6.0/results/2026-09-10-gis-mcp/adapters-naive.json +766 -0
  41. argleton-0.6.0/results/2026-09-10-gis-mcp/adapters-rasterio.json +767 -0
  42. argleton-0.6.0/results/2026-09-10-gis-mcp/adapters-whitebox.json +767 -0
  43. argleton-0.6.0/results/2026-09-15-qgis-three-ways/adapters-geopandas.json +767 -0
  44. argleton-0.6.0/results/2026-09-15-qgis-three-ways/adapters-gis-mcp.json +767 -0
  45. argleton-0.6.0/results/2026-09-15-qgis-three-ways/adapters-mapsmith.json +767 -0
  46. argleton-0.6.0/results/2026-09-15-qgis-three-ways/adapters-naive.json +766 -0
  47. argleton-0.6.0/results/2026-09-15-qgis-three-ways/adapters-qgis-agent-mcp.json +768 -0
  48. argleton-0.6.0/results/2026-09-15-qgis-three-ways/adapters-qgis-mcp.json +768 -0
  49. argleton-0.6.0/results/2026-09-15-qgis-three-ways/adapters-qgis.json +767 -0
  50. argleton-0.6.0/results/2026-09-15-qgis-three-ways/adapters-rasterio.json +767 -0
  51. argleton-0.6.0/results/2026-09-15-qgis-three-ways/adapters-whitebox.json +767 -0
  52. argleton-0.6.0/results/2026-09-26-trap-024-corrected/adapters-geopandas.json +767 -0
  53. argleton-0.6.0/results/2026-09-26-trap-024-corrected/adapters-gis-mcp.json +767 -0
  54. argleton-0.6.0/results/2026-09-26-trap-024-corrected/adapters-mapsmith.json +767 -0
  55. argleton-0.6.0/results/2026-09-26-trap-024-corrected/adapters-naive.json +766 -0
  56. argleton-0.6.0/results/2026-09-26-trap-024-corrected/adapters-qgis-agent-mcp.json +768 -0
  57. argleton-0.6.0/results/2026-09-26-trap-024-corrected/adapters-qgis-mcp.json +768 -0
  58. argleton-0.6.0/results/2026-09-26-trap-024-corrected/adapters-qgis.json +767 -0
  59. argleton-0.6.0/results/2026-09-26-trap-024-corrected/adapters-rasterio.json +767 -0
  60. argleton-0.6.0/results/2026-09-26-trap-024-corrected/adapters-whitebox.json +767 -0
  61. argleton-0.6.0/results/LATEST +1 -0
  62. {argleton-0.4.0 → argleton-0.6.0}/results/README.md +415 -32
  63. argleton-0.6.0/site/build.py +656 -0
  64. {argleton-0.4.0 → argleton-0.6.0}/site/index.template.html +33 -12
  65. argleton-0.6.0/tests/test_showcase.py +1422 -0
  66. argleton-0.6.0/tests/test_site_erratum.py +83 -0
  67. argleton-0.6.0/traps/024-pixel-is-point/README.md +121 -0
  68. {argleton-0.4.0 → argleton-0.6.0}/traps/024-pixel-is-point/build.py +13 -8
  69. argleton-0.6.0/traps/024-pixel-is-point/probe.toml +144 -0
  70. argleton-0.6.0/traps/031-hole-wound-as-shell/README.md +70 -0
  71. argleton-0.6.0/traps/031-hole-wound-as-shell/build.py +99 -0
  72. argleton-0.6.0/traps/031-hole-wound-as-shell/probe.toml +108 -0
  73. argleton-0.4.0/adapters/gis_mcp.py +0 -220
  74. argleton-0.4.0/argleton/__init__.py +0 -3
  75. argleton-0.4.0/results/LATEST +0 -1
  76. argleton-0.4.0/site/build.py +0 -246
  77. argleton-0.4.0/tests/test_showcase.py +0 -642
  78. argleton-0.4.0/traps/024-pixel-is-point/README.md +0 -111
  79. argleton-0.4.0/traps/024-pixel-is-point/probe.toml +0 -137
  80. {argleton-0.4.0 → argleton-0.6.0}/.gitattributes +0 -0
  81. {argleton-0.4.0 → argleton-0.6.0}/.github/workflows/pages.yml +0 -0
  82. {argleton-0.4.0 → argleton-0.6.0}/.gitignore +0 -0
  83. {argleton-0.4.0 → argleton-0.6.0}/LICENSE +0 -0
  84. {argleton-0.4.0 → argleton-0.6.0}/adapters/__init__.py +0 -0
  85. {argleton-0.4.0 → argleton-0.6.0}/adapters/engine_whitebox.py +0 -0
  86. {argleton-0.4.0 → argleton-0.6.0}/argleton/published.py +0 -0
  87. {argleton-0.4.0 → argleton-0.6.0}/argleton/score.py +0 -0
  88. {argleton-0.4.0 → argleton-0.6.0}/clean/c001-raster-mean/build.py +0 -0
  89. {argleton-0.4.0 → argleton-0.6.0}/clean/c001-raster-mean/probe.toml +0 -0
  90. {argleton-0.4.0 → argleton-0.6.0}/clean/c002-projected-area/build.py +0 -0
  91. {argleton-0.4.0 → argleton-0.6.0}/clean/c002-projected-area/probe.toml +0 -0
  92. {argleton-0.4.0 → argleton-0.6.0}/clean/c003-raster-mean-nodata/build.py +0 -0
  93. {argleton-0.4.0 → argleton-0.6.0}/clean/c003-raster-mean-nodata/probe.toml +0 -0
  94. {argleton-0.4.0 → argleton-0.6.0}/clean/c004-points-in-polygon/build.py +0 -0
  95. {argleton-0.4.0 → argleton-0.6.0}/clean/c004-points-in-polygon/probe.toml +0 -0
  96. {argleton-0.4.0 → argleton-0.6.0}/clean/c005-polygon-area/build.py +0 -0
  97. {argleton-0.4.0 → argleton-0.6.0}/clean/c005-polygon-area/probe.toml +0 -0
  98. {argleton-0.4.0 → argleton-0.6.0}/clean/c006-named-layer/build.py +0 -0
  99. {argleton-0.4.0 → argleton-0.6.0}/clean/c006-named-layer/probe.toml +0 -0
  100. {argleton-0.4.0 → argleton-0.6.0}/clean/c007-distance-in-metres/build.py +0 -0
  101. {argleton-0.4.0 → argleton-0.6.0}/clean/c007-distance-in-metres/probe.toml +0 -0
  102. {argleton-0.4.0 → argleton-0.6.0}/clean/c008-equal-area-crs/build.py +0 -0
  103. {argleton-0.4.0 → argleton-0.6.0}/clean/c008-equal-area-crs/probe.toml +0 -0
  104. {argleton-0.4.0 → argleton-0.6.0}/clean/c009-native-resolution-classes/build.py +0 -0
  105. {argleton-0.4.0 → argleton-0.6.0}/clean/c009-native-resolution-classes/probe.toml +0 -0
  106. {argleton-0.4.0 → argleton-0.6.0}/clean/c010-physical-values/build.py +0 -0
  107. {argleton-0.4.0 → argleton-0.6.0}/clean/c010-physical-values/probe.toml +0 -0
  108. {argleton-0.4.0 → argleton-0.6.0}/clean/c011-solid-parcel/build.py +0 -0
  109. {argleton-0.4.0 → argleton-0.6.0}/clean/c011-solid-parcel/probe.toml +0 -0
  110. {argleton-0.4.0 → argleton-0.6.0}/clean/c012-disjoint-concessions/build.py +0 -0
  111. {argleton-0.4.0 → argleton-0.6.0}/clean/c012-disjoint-concessions/probe.toml +0 -0
  112. {argleton-0.4.0 → argleton-0.6.0}/clean/c013-flat-pipeline/build.py +0 -0
  113. {argleton-0.4.0 → argleton-0.6.0}/clean/c013-flat-pipeline/probe.toml +0 -0
  114. {argleton-0.4.0 → argleton-0.6.0}/clean/c014-convex-parcel/build.py +0 -0
  115. {argleton-0.4.0 → argleton-0.6.0}/clean/c014-convex-parcel/probe.toml +0 -0
  116. {argleton-0.4.0 → argleton-0.6.0}/clean/c015-wells-off-the-seam/build.py +0 -0
  117. {argleton-0.4.0 → argleton-0.6.0}/clean/c015-wells-off-the-seam/probe.toml +0 -0
  118. {argleton-0.4.0 → argleton-0.6.0}/clean/c016-decimal-degrees/build.py +0 -0
  119. {argleton-0.4.0 → argleton-0.6.0}/clean/c016-decimal-degrees/probe.toml +0 -0
  120. {argleton-0.4.0 → argleton-0.6.0}/clean/c017-equal-populations/build.py +0 -0
  121. {argleton-0.4.0 → argleton-0.6.0}/clean/c017-equal-populations/probe.toml +0 -0
  122. {argleton-0.4.0 → argleton-0.6.0}/clean/c018-plain-keys/build.py +0 -0
  123. {argleton-0.4.0 → argleton-0.6.0}/clean/c018-plain-keys/probe.toml +0 -0
  124. {argleton-0.4.0 → argleton-0.6.0}/clean/c019-fully-contained/build.py +0 -0
  125. {argleton-0.4.0 → argleton-0.6.0}/clean/c019-fully-contained/probe.toml +0 -0
  126. {argleton-0.4.0 → argleton-0.6.0}/clean/c020-one-owner-each/build.py +0 -0
  127. {argleton-0.4.0 → argleton-0.6.0}/clean/c020-one-owner-each/probe.toml +0 -0
  128. {argleton-0.4.0 → argleton-0.6.0}/clean/c021-greenwich-variant/build.py +0 -0
  129. {argleton-0.4.0 → argleton-0.6.0}/clean/c021-greenwich-variant/probe.toml +0 -0
  130. {argleton-0.4.0 → argleton-0.6.0}/clean/c022-two-gauges/build.py +0 -0
  131. {argleton-0.4.0 → argleton-0.6.0}/clean/c022-two-gauges/probe.toml +0 -0
  132. {argleton-0.4.0 → argleton-0.6.0}/clean/c023-longitude-first/build.py +0 -0
  133. {argleton-0.4.0 → argleton-0.6.0}/clean/c023-longitude-first/probe.toml +0 -0
  134. {argleton-0.4.0 → argleton-0.6.0}/clean/c025-single-hemisphere-zone/build.py +0 -0
  135. {argleton-0.4.0 → argleton-0.6.0}/clean/c025-single-hemisphere-zone/probe.toml +0 -0
  136. {argleton-0.4.0 → argleton-0.6.0}/clean/c026-north-up-grid/build.py +0 -0
  137. {argleton-0.4.0 → argleton-0.6.0}/clean/c026-north-up-grid/probe.toml +0 -0
  138. {argleton-0.4.0 → argleton-0.6.0}/clean/c027-lines-only/build.py +0 -0
  139. {argleton-0.4.0 → argleton-0.6.0}/clean/c027-lines-only/probe.toml +0 -0
  140. {argleton-0.4.0 → argleton-0.6.0}/clean/c028-projected-field/build.py +0 -0
  141. {argleton-0.4.0 → argleton-0.6.0}/clean/c028-projected-field/probe.toml +0 -0
  142. {argleton-0.4.0 → argleton-0.6.0}/clean/c029-coincident-boundaries/build.py +0 -0
  143. {argleton-0.4.0 → argleton-0.6.0}/clean/c029-coincident-boundaries/probe.toml +0 -0
  144. {argleton-0.4.0 → argleton-0.6.0}/clean/c030-single-georeferencing/build.py +0 -0
  145. {argleton-0.4.0 → argleton-0.6.0}/clean/c030-single-georeferencing/probe.toml +0 -0
  146. {argleton-0.4.0 → argleton-0.6.0}/docs/ADDING-A-TRAP.md +0 -0
  147. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-23-first-run/adapters-mapsmith.json +0 -0
  148. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-23-first-run/engine-geopandas.json +0 -0
  149. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-23-first-run/engine-naive.json +0 -0
  150. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-23-first-run/engine-rasterio.json +0 -0
  151. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-23-first-run/engine-whitebox.json +0 -0
  152. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-24-five-families/adapters-mapsmith.json +0 -0
  153. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-24-five-families/engine-geopandas.json +0 -0
  154. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-24-five-families/engine-naive.json +0 -0
  155. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-24-five-families/engine-rasterio.json +0 -0
  156. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-24-five-families/engine-whitebox.json +0 -0
  157. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-25-eight-families/adapters-mapsmith.json +0 -0
  158. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-25-eight-families/engine-geopandas.json +0 -0
  159. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-25-eight-families/engine-naive.json +0 -0
  160. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-25-eight-families/engine-rasterio.json +0 -0
  161. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-25-eight-families/engine-whitebox.json +0 -0
  162. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-25-six-families/adapters-mapsmith.json +0 -0
  163. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-25-six-families/engine-geopandas.json +0 -0
  164. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-25-six-families/engine-naive.json +0 -0
  165. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-25-six-families/engine-rasterio.json +0 -0
  166. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-25-six-families/engine-whitebox.json +0 -0
  167. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-eighteen-families/adapters-geopandas.json +0 -0
  168. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-eighteen-families/adapters-mapsmith.json +0 -0
  169. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-eighteen-families/adapters-naive.json +0 -0
  170. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-eighteen-families/adapters-rasterio.json +0 -0
  171. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-eighteen-families/adapters-whitebox.json +0 -0
  172. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-nine-families/adapters-geopandas.json +0 -0
  173. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-nine-families/adapters-mapsmith.json +0 -0
  174. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-nine-families/adapters-naive.json +0 -0
  175. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-nine-families/adapters-rasterio.json +0 -0
  176. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-nine-families/adapters-whitebox.json +0 -0
  177. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-nineteen-families/adapters-geopandas.json +0 -0
  178. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-nineteen-families/adapters-mapsmith.json +0 -0
  179. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-nineteen-families/adapters-naive.json +0 -0
  180. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-nineteen-families/adapters-rasterio.json +0 -0
  181. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-nineteen-families/adapters-whitebox.json +0 -0
  182. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-ten-families/adapters-geopandas.json +0 -0
  183. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-ten-families/adapters-mapsmith.json +0 -0
  184. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-ten-families/adapters-naive.json +0 -0
  185. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-ten-families/adapters-rasterio.json +0 -0
  186. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-26-ten-families/adapters-whitebox.json +0 -0
  187. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-27-datum-shift-fixed/adapters-geopandas.json +0 -0
  188. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-27-datum-shift-fixed/adapters-mapsmith.json +0 -0
  189. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-27-datum-shift-fixed/adapters-naive.json +0 -0
  190. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-27-datum-shift-fixed/adapters-rasterio.json +0 -0
  191. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-27-datum-shift-fixed/adapters-whitebox.json +0 -0
  192. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-28-thiessen-pairing/adapters-geopandas.json +0 -0
  193. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-28-thiessen-pairing/adapters-mapsmith.json +0 -0
  194. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-28-thiessen-pairing/adapters-naive.json +0 -0
  195. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-28-thiessen-pairing/adapters-rasterio.json +0 -0
  196. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-28-thiessen-pairing/adapters-whitebox.json +0 -0
  197. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-28-timings/adapters-geopandas.json +0 -0
  198. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-28-timings/adapters-mapsmith.json +0 -0
  199. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-28-timings/adapters-naive.json +0 -0
  200. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-28-timings/adapters-rasterio.json +0 -0
  201. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-28-timings/adapters-whitebox.json +0 -0
  202. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-29-axis-order/adapters-geopandas.json +0 -0
  203. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-29-axis-order/adapters-mapsmith.json +0 -0
  204. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-29-axis-order/adapters-naive.json +0 -0
  205. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-29-axis-order/adapters-rasterio.json +0 -0
  206. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-29-axis-order/adapters-whitebox.json +0 -0
  207. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-30-all-families/adapters-geopandas.json +0 -0
  208. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-30-all-families/adapters-mapsmith.json +0 -0
  209. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-30-all-families/adapters-naive.json +0 -0
  210. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-30-all-families/adapters-rasterio.json +0 -0
  211. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-30-all-families/adapters-whitebox.json +0 -0
  212. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-30-antimeridian/adapters-geopandas.json +0 -0
  213. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-30-antimeridian/adapters-mapsmith.json +0 -0
  214. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-30-antimeridian/adapters-naive.json +0 -0
  215. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-30-antimeridian/adapters-rasterio.json +0 -0
  216. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-30-antimeridian/adapters-whitebox.json +0 -0
  217. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-30-grid-registration/adapters-geopandas.json +0 -0
  218. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-30-grid-registration/adapters-mapsmith.json +0 -0
  219. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-30-grid-registration/adapters-naive.json +0 -0
  220. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-30-grid-registration/adapters-rasterio.json +0 -0
  221. {argleton-0.4.0 → argleton-0.6.0}/results/2026-08-30-grid-registration/adapters-whitebox.json +0 -0
  222. {argleton-0.4.0 → argleton-0.6.0}/schema/probe.schema.json +0 -0
  223. {argleton-0.4.0 → argleton-0.6.0}/schema/result.schema.json +0 -0
  224. {argleton-0.4.0 → argleton-0.6.0}/tests/test_contracts.py +0 -0
  225. {argleton-0.4.0 → argleton-0.6.0}/traps/001-tiff-predictor/README.md +0 -0
  226. {argleton-0.4.0 → argleton-0.6.0}/traps/001-tiff-predictor/build.py +0 -0
  227. {argleton-0.4.0 → argleton-0.6.0}/traps/001-tiff-predictor/probe.toml +0 -0
  228. {argleton-0.4.0 → argleton-0.6.0}/traps/002-feet-as-metres/README.md +0 -0
  229. {argleton-0.4.0 → argleton-0.6.0}/traps/002-feet-as-metres/build.py +0 -0
  230. {argleton-0.4.0 → argleton-0.6.0}/traps/002-feet-as-metres/probe.toml +0 -0
  231. {argleton-0.4.0 → argleton-0.6.0}/traps/003-nodata-in-statistics/README.md +0 -0
  232. {argleton-0.4.0 → argleton-0.6.0}/traps/003-nodata-in-statistics/build.py +0 -0
  233. {argleton-0.4.0 → argleton-0.6.0}/traps/003-nodata-in-statistics/probe.toml +0 -0
  234. {argleton-0.4.0 → argleton-0.6.0}/traps/004-mismatched-crs-join/README.md +0 -0
  235. {argleton-0.4.0 → argleton-0.6.0}/traps/004-mismatched-crs-join/build.py +0 -0
  236. {argleton-0.4.0 → argleton-0.6.0}/traps/004-mismatched-crs-join/probe.toml +0 -0
  237. {argleton-0.4.0 → argleton-0.6.0}/traps/005-bowtie-area/README.md +0 -0
  238. {argleton-0.4.0 → argleton-0.6.0}/traps/005-bowtie-area/build.py +0 -0
  239. {argleton-0.4.0 → argleton-0.6.0}/traps/005-bowtie-area/probe.toml +0 -0
  240. {argleton-0.4.0 → argleton-0.6.0}/traps/006-default-layer/README.md +0 -0
  241. {argleton-0.4.0 → argleton-0.6.0}/traps/006-default-layer/build.py +0 -0
  242. {argleton-0.4.0 → argleton-0.6.0}/traps/006-default-layer/probe.toml +0 -0
  243. {argleton-0.4.0 → argleton-0.6.0}/traps/007-buffer-in-degrees/README.md +0 -0
  244. {argleton-0.4.0 → argleton-0.6.0}/traps/007-buffer-in-degrees/build.py +0 -0
  245. {argleton-0.4.0 → argleton-0.6.0}/traps/007-buffer-in-degrees/probe.toml +0 -0
  246. {argleton-0.4.0 → argleton-0.6.0}/traps/008-web-mercator-area/README.md +0 -0
  247. {argleton-0.4.0 → argleton-0.6.0}/traps/008-web-mercator-area/build.py +0 -0
  248. {argleton-0.4.0 → argleton-0.6.0}/traps/008-web-mercator-area/probe.toml +0 -0
  249. {argleton-0.4.0 → argleton-0.6.0}/traps/009-resampled-classes/README.md +0 -0
  250. {argleton-0.4.0 → argleton-0.6.0}/traps/009-resampled-classes/build.py +0 -0
  251. {argleton-0.4.0 → argleton-0.6.0}/traps/009-resampled-classes/probe.toml +0 -0
  252. {argleton-0.4.0 → argleton-0.6.0}/traps/010-scale-offset/README.md +0 -0
  253. {argleton-0.4.0 → argleton-0.6.0}/traps/010-scale-offset/build.py +0 -0
  254. {argleton-0.4.0 → argleton-0.6.0}/traps/010-scale-offset/probe.toml +0 -0
  255. {argleton-0.4.0 → argleton-0.6.0}/traps/011-polygon-holes/README.md +0 -0
  256. {argleton-0.4.0 → argleton-0.6.0}/traps/011-polygon-holes/build.py +0 -0
  257. {argleton-0.4.0 → argleton-0.6.0}/traps/011-polygon-holes/probe.toml +0 -0
  258. {argleton-0.4.0 → argleton-0.6.0}/traps/012-double-counting/README.md +0 -0
  259. {argleton-0.4.0 → argleton-0.6.0}/traps/012-double-counting/build.py +0 -0
  260. {argleton-0.4.0 → argleton-0.6.0}/traps/012-double-counting/probe.toml +0 -0
  261. {argleton-0.4.0 → argleton-0.6.0}/traps/013-z-dimension/README.md +0 -0
  262. {argleton-0.4.0 → argleton-0.6.0}/traps/013-z-dimension/build.py +0 -0
  263. {argleton-0.4.0 → argleton-0.6.0}/traps/013-z-dimension/probe.toml +0 -0
  264. {argleton-0.4.0 → argleton-0.6.0}/traps/014-centroid-outside/README.md +0 -0
  265. {argleton-0.4.0 → argleton-0.6.0}/traps/014-centroid-outside/build.py +0 -0
  266. {argleton-0.4.0 → argleton-0.6.0}/traps/014-centroid-outside/probe.toml +0 -0
  267. {argleton-0.4.0 → argleton-0.6.0}/traps/015-boundary-semantics/README.md +0 -0
  268. {argleton-0.4.0 → argleton-0.6.0}/traps/015-boundary-semantics/build.py +0 -0
  269. {argleton-0.4.0 → argleton-0.6.0}/traps/015-boundary-semantics/probe.toml +0 -0
  270. {argleton-0.4.0 → argleton-0.6.0}/traps/016-coordinate-parsing/README.md +0 -0
  271. {argleton-0.4.0 → argleton-0.6.0}/traps/016-coordinate-parsing/build.py +0 -0
  272. {argleton-0.4.0 → argleton-0.6.0}/traps/016-coordinate-parsing/probe.toml +0 -0
  273. {argleton-0.4.0 → argleton-0.6.0}/traps/017-aggregation-weighting/README.md +0 -0
  274. {argleton-0.4.0 → argleton-0.6.0}/traps/017-aggregation-weighting/build.py +0 -0
  275. {argleton-0.4.0 → argleton-0.6.0}/traps/017-aggregation-weighting/probe.toml +0 -0
  276. {argleton-0.4.0 → argleton-0.6.0}/traps/018-join-key-typing/README.md +0 -0
  277. {argleton-0.4.0 → argleton-0.6.0}/traps/018-join-key-typing/build.py +0 -0
  278. {argleton-0.4.0 → argleton-0.6.0}/traps/018-join-key-typing/probe.toml +0 -0
  279. {argleton-0.4.0 → argleton-0.6.0}/traps/019-partial-overlap/README.md +0 -0
  280. {argleton-0.4.0 → argleton-0.6.0}/traps/019-partial-overlap/build.py +0 -0
  281. {argleton-0.4.0 → argleton-0.6.0}/traps/019-partial-overlap/probe.toml +0 -0
  282. {argleton-0.4.0 → argleton-0.6.0}/traps/020-join-cardinality/README.md +0 -0
  283. {argleton-0.4.0 → argleton-0.6.0}/traps/020-join-cardinality/build.py +0 -0
  284. {argleton-0.4.0 → argleton-0.6.0}/traps/020-join-cardinality/probe.toml +0 -0
  285. {argleton-0.4.0 → argleton-0.6.0}/traps/021-ballpark-datum/README.md +0 -0
  286. {argleton-0.4.0 → argleton-0.6.0}/traps/021-ballpark-datum/build.py +0 -0
  287. {argleton-0.4.0 → argleton-0.6.0}/traps/021-ballpark-datum/probe.toml +0 -0
  288. {argleton-0.4.0 → argleton-0.6.0}/traps/022-thiessen-pairing/README.md +0 -0
  289. {argleton-0.4.0 → argleton-0.6.0}/traps/022-thiessen-pairing/build.py +0 -0
  290. {argleton-0.4.0 → argleton-0.6.0}/traps/022-thiessen-pairing/probe.toml +0 -0
  291. {argleton-0.4.0 → argleton-0.6.0}/traps/023-axis-order/README.md +0 -0
  292. {argleton-0.4.0 → argleton-0.6.0}/traps/023-axis-order/build.py +0 -0
  293. {argleton-0.4.0 → argleton-0.6.0}/traps/023-axis-order/probe.toml +0 -0
  294. {argleton-0.4.0 → argleton-0.6.0}/traps/025-antimeridian-zone/README.md +0 -0
  295. {argleton-0.4.0 → argleton-0.6.0}/traps/025-antimeridian-zone/build.py +0 -0
  296. {argleton-0.4.0 → argleton-0.6.0}/traps/025-antimeridian-zone/probe.toml +0 -0
  297. {argleton-0.4.0 → argleton-0.6.0}/traps/026-south-up-grid/README.md +0 -0
  298. {argleton-0.4.0 → argleton-0.6.0}/traps/026-south-up-grid/build.py +0 -0
  299. {argleton-0.4.0 → argleton-0.6.0}/traps/026-south-up-grid/probe.toml +0 -0
  300. {argleton-0.4.0 → argleton-0.6.0}/traps/027-mixed-geometry/README.md +0 -0
  301. {argleton-0.4.0 → argleton-0.6.0}/traps/027-mixed-geometry/build.py +0 -0
  302. {argleton-0.4.0 → argleton-0.6.0}/traps/027-mixed-geometry/probe.toml +0 -0
  303. {argleton-0.4.0 → argleton-0.6.0}/traps/028-degrees-as-metres/README.md +0 -0
  304. {argleton-0.4.0 → argleton-0.6.0}/traps/028-degrees-as-metres/build.py +0 -0
  305. {argleton-0.4.0 → argleton-0.6.0}/traps/028-degrees-as-metres/probe.toml +0 -0
  306. {argleton-0.4.0 → argleton-0.6.0}/traps/029-difference-order/README.md +0 -0
  307. {argleton-0.4.0 → argleton-0.6.0}/traps/029-difference-order/build.py +0 -0
  308. {argleton-0.4.0 → argleton-0.6.0}/traps/029-difference-order/probe.toml +0 -0
  309. {argleton-0.4.0 → argleton-0.6.0}/traps/030-sidecar-georeferencing/README.md +0 -0
  310. {argleton-0.4.0 → argleton-0.6.0}/traps/030-sidecar-georeferencing/build.py +0 -0
  311. {argleton-0.4.0 → argleton-0.6.0}/traps/030-sidecar-georeferencing/probe.toml +0 -0
@@ -82,13 +82,21 @@ jobs:
82
82
  # point — a trap that stops catching its own naive adapter, or one
83
83
  # that starts catching a case it should not, has changed what it
84
84
  # measures, and that must be a decision rather than a surprise.
85
- # 0.9333 = 28 of 30 traps caught. TWO still pass, unchanged: 001,
86
- # where rasterio undoes the predictor on the naive adapter's behalf,
87
- # and 026, where `src.res` reports the cell size faithfully whichever
88
- # way the rows run — so a plain numpy gradient is more faithful to the
89
- # geotransform than a specialised terrain engine is. Moved from 0.931
90
- # on 2026-08-31 when trap 030 added family 28: the naive adapter falls
91
- # into it, so both numerator and denominator went up by one. Before
85
+ # 0.9032 = 28 of 31 traps caught. THREE pass: 001, where rasterio
86
+ # undoes the predictor on the naive adapter's behalf; 026, where
87
+ # `src.res` reports the cell size faithfully whichever way the rows
88
+ # run — so a plain numpy gradient is more faithful to the geotransform
89
+ # than a specialised terrain engine is; and 024, where `src.xy` is
90
+ # right because GDAL has already folded PixelIsPoint into the
91
+ # geotransform. Moved from 0.9355 on 2026-09-25, and not because a
92
+ # trap was added: 024's truth was wrong, and the naive composition had
93
+ # been scored `silent_error` for the right answer since 2026-08-30
94
+ # (results/README.md, erratum). Moved from
95
+ # 0.9333 on 2026-09-02 when trap 031 added family 29 — a shapefile
96
+ # whose inner ring is wound like its outer one, which the naive
97
+ # composition reads as two shells and adds — so both numerator and
98
+ # denominator went up by one. Before that 0.931 on 2026-08-31 when
99
+ # trap 030 added family 28, the same way. Before
92
100
  # that 0.96 when traps 026 to 029 closed the original family list, and
93
101
  # 0.9583, 0.9565 and 0.9545 as traps 025, 024 and 023 landed.
94
102
  # Each time the denominator changed and the numerator changed with
@@ -96,5 +104,5 @@ jobs:
96
104
  # mechanism working — the number moved because a trap was added, which
97
105
  # is a decision, and it has to be written down here rather than
98
106
  # discovered in a published table.
99
- sys.exit(0 if (r["silent_error_rate"], r["completion_rate"]) == (0.9333, 1.0) else 1)
107
+ sys.exit(0 if (r["silent_error_rate"], r["completion_rate"]) == (0.9032, 1.0) else 1)
100
108
  PY
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "upload_type": "software",
3
3
  "title": "Argleton: a correctness suite for geospatial systems",
4
- "version": "0.4.0",
4
+ "version": "0.6.0",
5
5
  "creators": [
6
6
  {"name": "The Argleton project"}
7
7
  ],
@@ -0,0 +1,139 @@
1
+ # Changelog
2
+
3
+ All notable changes to Argleton are documented here, in the format of
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). This project follows
5
+ [semantic versioning](https://semver.org/).
6
+
7
+ This file starts at 0.5.0. Releases before it are described by their tags and
8
+ by the dated sections of [`results/README.md`](results/README.md), which is
9
+ where this project's findings have always been written — the omission was that
10
+ a reader had nowhere to see, in one place, what changed between two versions of
11
+ the suite itself.
12
+
13
+ ## [Unreleased]
14
+
15
+ Nothing yet.
16
+
17
+ ## [0.6.0] - 2026-09-26
18
+
19
+ A correction release. Trap 024's truth was wrong from 2026-08-30, in favour of
20
+ the systems that corrected a half cell twice and against the ones that were
21
+ right; this release carries the corrected truth, the erratum, and the first run
22
+ scored against it (`2026-09-26-trap-024-corrected`). A result computed with
23
+ 0.5.0 on trap 024 is not comparable with one computed now, which is why this is
24
+ a minor version and not a patch.
25
+
26
+ ### Fixed
27
+
28
+ - **Trap 024's truth was wrong, from 2026-08-30.** It said the lowest cell of
29
+ `hollow.tif` is at 412090; the file says 412105. The premise was a sentence
30
+ that GDAL "leaves the geotransform alone" for a PixelIsPoint file, which GDAL
31
+ documents the other way (RFC 33): it moves the stored tie point half a cell on
32
+ write and on read. Systems that answered correctly -- the naive composition,
33
+ and the three QGIS rows -- were scored `silent_error`; MapSmith and the rasterio
34
+ adapter, which corrected the half cell a second time, were scored `correct`.
35
+ The fixture is unchanged. The truth, the README, the clean twin's derivation
36
+ and `FAMILIES.md` are corrected; the rasterio adapter no longer corrects
37
+ twice; the published runs are left as they were, with an erratum in
38
+ `results/README.md` recounting them. The trap's accepted refusals are
39
+ narrowed with it: the file has one answer, so a refusal counts only when it
40
+ names what goes wrong (a raw tie point read as a corner, or a correction made
41
+ twice), not when it says "pixel is point". argleton.org rescores the published
42
+ run against the truths in the tree with the runner's own comparison, traps
43
+ only, and says nothing once a run agrees with them.
44
+
45
+ ## [0.5.0] - 2026-09-21
46
+
47
+ Thirty-one commits since 0.4.0. The headline is that a third-party system was
48
+ measured against the engine it wraps, for the first time, and the result is
49
+ that the wrapper is not the thing to blame.
50
+
51
+ ### Added
52
+
53
+ - **Three QGIS rows, and they are the same QGIS.** The processing engine driven
54
+ headless through `qgis_process`, and the two MCP servers that run inside a
55
+ live QGIS and forward to it — `nkarasiak/qgis-mcp` 0.14.0 over its plugin
56
+ socket, QGIS Agent MCP 0.5.0 over its local bridge. All three answer **every
57
+ one of the thirty-one traps**, nothing unsupported, and all three come out at
58
+ the same silent-error rate of **0.3871**.
59
+
60
+ That equality is the finding, and it is only readable because the engine has
61
+ a row of its own: the wrappers inherit it, neither adding a correct answer
62
+ nor losing one. Without the engine's row, three equal numbers read as three
63
+ equally defective servers, and that reading would be wrong. The engine's row
64
+ was built first for exactly this reason.
65
+
66
+ The chains are shared by all three adapters in one file, so a difference
67
+ between the rows can only come from the system rather than from a chain that
68
+ drifted between copies.
69
+
70
+ - **`gis-mcp` 0.15.0**, the first system here whose defects are not ours to
71
+ fix, published on 2026-09-10 after its maintainer was told first.
72
+
73
+ - **Family 29, `ring-role-by-winding`.** A shapefile carries no nesting, so
74
+ which ring is a hole is decided by the direction it is wound and by nothing
75
+ else. An inner ring wound like its parent reads as a second shell and its
76
+ area is added: 31000 m² where the truth is 29000, +6.9% in the owner's
77
+ favour, with the right bounding box, the right CRS and no warning.
78
+
79
+ ### Changed
80
+
81
+ - **`argleton.__version__` is derived instead of written.** It answered
82
+ `0.1.0.dev0` while 0.4.0 was on PyPI, across four releases, because the
83
+ number lived in two places and only one was on a checklist. Nothing inside
84
+ the package read it, so nothing caught it. It now comes from the installed
85
+ distribution, or from `pyproject.toml` when running from a checkout, and a
86
+ test compares the two.
87
+
88
+ - **The naive baseline pin moves to 0.9355**, which is the pin doing its job
89
+ rather than a number being adjusted: the denominator grew when the suite
90
+ reached thirty-one traps.
91
+
92
+ - **A fixture build that dies with no output is retried on its signature, not
93
+ on a count.** One retry had been calibrated against 370 builds, where a
94
+ doubled failure is about one in a thousand. At nine adapters and 558 builds
95
+ the same doubled failure is about one in twenty. The constant was not wrong
96
+ when it was written; it went wrong when the table grew, and nothing was
97
+ watching it. The retry now keys on what the death looks like — both output
98
+ streams empty, because the process never ran — which is stricter than what it
99
+ replaces: a builder that fails while saying something now fails on the first
100
+ attempt.
101
+
102
+ ### Fixed
103
+
104
+ - **The site sorted both QGIS MCP servers below the naive baseline**, the row
105
+ that exists to be the worst line on the page, because neither matched a
106
+ prefix in the ordering list and an unmatched row sorts last. The comment
107
+ above that list had named their correct place two months earlier — beside
108
+ `gis-mcp`, with the engine they call directly underneath. A rule stated in a
109
+ comment and not executed by code is not a rule; a test covers it now.
110
+
111
+ - **The site said "every system here completes every clean probe"** directly
112
+ under a column showing two systems that do not.
113
+
114
+ - **Three surfaces said every number comes from calling code in the same
115
+ process rather than over a transport.** Two rows are a TCP socket and a local
116
+ bridge into a live QGIS, which is what their own labels say.
117
+
118
+ - **The results page said we had "found nothing of its own" about one wrapper**,
119
+ seven lines after describing a property of that wrapper. The true sentence is
120
+ "nothing that makes an answer wrong", and the notification rule is restated
121
+ around it.
122
+
123
+ - **"In opposite directions" described two rows with the same probe, the same
124
+ verdict and the same completion rate.** They differ in how they fail.
125
+
126
+ - **`FAMILIES.md` published four false sentences about its own count** while
127
+ two guards on counts were green, because they watched three other sentence
128
+ shapes. The numbers are derived now, and an unexplained spelled-out number in
129
+ that file is a failure rather than a gap.
130
+
131
+ - **The results index counts its own rows** instead of only checking the ones
132
+ that happen to be listed, and the tool count is asked of the server rather
133
+ than written down.
134
+
135
+ - **`publish_run.py`** — in the private workspace, but its effects are here —
136
+ refuses to publish an adapter whose failures all carry one message: that is a
137
+ system we could not reach, not a system that got things wrong. A run was
138
+ minutes from publishing `completion 0.2258` for a third-party server whose
139
+ 62 probes had all failed to connect.
@@ -5,10 +5,15 @@ type: software
5
5
  authors:
6
6
  - name: "The Argleton project"
7
7
  repository-code: "https://github.com/argleton/argleton"
8
+ doi: "10.5281/zenodo.22206349"
9
+ identifiers:
10
+ - type: doi
11
+ value: "10.5281/zenodo.22206349"
12
+ description: "Concept DOI — always resolves to the latest release"
8
13
  url: "https://argleton.org"
9
14
  license: Apache-2.0
10
- version: "0.4.0"
11
- date-released: "2026-08-31"
15
+ version: "0.6.0"
16
+ date-released: "2026-09-26"
12
17
  abstract: >-
13
18
  Probes whose right answer is known by construction — derived on paper, never
14
19
  measured from a reference implementation — and whose typical wrong answer
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: argleton
3
- Version: 0.4.0
3
+ Version: 0.6.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
@@ -42,7 +42,15 @@ known by construction, and every trap has a *wrong* answer that looks fine.
42
42
  **[argleton.org](https://argleton.org)** — the current results, rendered by CI
43
43
  from this repository's own numbers. Nothing on that page is typed in by hand.
44
44
 
45
- That second half is the whole point. Existing benchmarks for geospatial agents
45
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.22206349.svg)](https://doi.org/10.5281/zenodo.22206349)
46
+
47
+ Cite it as `10.5281/zenodo.22206349`, which always resolves to the current release. To cite the
48
+ exact version you measured against, take the version DOI from the
49
+ [Zenodo record](https://doi.org/10.5281/zenodo.22206349) — which is the same reason every run
50
+ here pins its `spec_commit`.
51
+
52
+ The second half of that first sentence — a *wrong* answer that looks fine — is
53
+ the whole point. Existing benchmarks for geospatial agents
46
54
  score trajectories: did it pick the right tools, in the right order, and produce
47
55
  a file? A system can score full marks on all of that and hand you a number that
48
56
  is wrong — no crash, no warning, no exception, nothing in the log. Nobody
@@ -67,10 +75,12 @@ machine, so there is nothing to download and nothing to take on trust:
67
75
  pip install "argleton[fixtures]"
68
76
  ```
69
77
 
70
- The probes ship with the runner, so that is the whole setup — release 0.4.0 carries the
71
- 30 traps and 28 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.
78
+ The probes ship with the runner, so that is the whole setup — release 0.6.0 carries the
79
+ 31 traps and 29 families the published table further down was run over, with trap 024's
80
+ corrected truth, so installing it and rerunning reproduces that table rather than a version of
81
+ it. (0.5.0 carries the old truth and would not.) Whenever the checkout here runs
82
+ ahead of the release, this paragraph says so and gives both counts, because a reader who cannot
83
+ reproduce the table on this page has been told something untrue.
74
84
 
75
85
  To read the probes, change them, or add one, take the checkout instead — the probes are the point of the
76
86
  repository and `probe.toml` is meant to be read:
@@ -83,29 +93,31 @@ pip install -e ".[fixtures]"
83
93
 
84
94
  ```
85
95
  $ argleton --adapter engine:rasterio
86
- ok clean c001-raster-mean correct 1093.0
87
- ok clean c003-raster-mean-nodata correct 1000.0
88
- ok clean c009-native-resolution-classes correct 900.0
89
- ok clean c010-physical-values correct 0.5000000093132254
90
- ok clean c024-pixel-is-area correct 412105.0
91
- ok clean c026-north-up-grid correct 5.710593137499643
92
- ok trap 001-tiff-predictor correct 1093.0
93
- ok trap 003-nodata-in-statistics correct 1000.0
94
- ok trap 009-resampled-classes correct 0.0
95
- ok trap 010-scale-offset correct 0.3333333333333334
96
- ok trap 024-pixel-is-point correct 412090.0
97
- ok trap 026-south-up-grid correct 5.710593137499643
98
- silent_error_rate 0.0 over 6 traps | completion_rate 1.0 over 6 clean
96
+ ok clean c001-raster-mean correct 1093.0
97
+ ok clean c003-raster-mean-nodata correct 1000.0
98
+ ok clean c009-native-resolution-classes correct 900.0
99
+ ok clean c010-physical-values correct 0.5000000093132254
100
+ ok clean c024-pixel-is-area correct 412105.0
101
+ ok clean c026-north-up-grid correct 5.710593137499643
102
+ ok clean c030-single-georeferencing correct_with_warning read with internal georeferencing
103
+ ok trap 001-tiff-predictor correct 1093.0
104
+ ok trap 003-nodata-in-statistics correct 1000.0
105
+ ok trap 009-resampled-classes correct 0.0
106
+ ok trap 010-scale-offset correct 0.3333333333333334
107
+ ok trap 024-pixel-is-point correct 412105.0
108
+ ok trap 026-south-up-grid correct 5.710593137499643
109
+ ok trap 030-sidecar-georeferencing correct_with_warning read with internal georeferencing; terrain.tif.aux.x
110
+ silent_error_rate 0.0 over 7 traps | completion_rate 1.0 over 7 clean
99
111
 
100
112
  $ argleton --adapter engine:whitebox
101
113
  ok clean c001-raster-mean correct 1093.0
102
114
  ok clean c003-raster-mean-nodata correct 1000.0
103
115
  ok clean c024-pixel-is-area correct 412105.0
104
116
  ok clean c026-north-up-grid correct 5.56521959900856
105
- FAIL trap 001-tiff-predictor silent_error expected 1093.0 ± 0.001, got 36.09375 — this is the
117
+ FAIL trap 001-tiff-predictor silent_error expected 1093.0 ± 0.001, got 36.09375 — this is the
106
118
  ok trap 003-nodata-in-statistics correct 1000.0
107
- FAIL trap 024-pixel-is-point silent_error expected 412090.0 ± 1.0, got 412120.0
108
- FAIL trap 026-south-up-grid silent_error expected 5.64 ± 0.2, got 43.99398475646973 — this is
119
+ FAIL trap 024-pixel-is-point silent_error expected 412105.0 ± 1.0, got 412120.0
120
+ FAIL trap 026-south-up-grid silent_error expected 5.64 ± 0.2, got 43.99398475646973 — this is
109
121
  silent_error_rate 0.75 over 4 traps | completion_rate 1.0 over 4 clean
110
122
  ```
111
123
 
@@ -119,20 +131,23 @@ silently wrong (the 0.75).
119
131
  The last two probes are worth reading twice, because the two engines part
120
132
  company on both. One file declares that its values sit at grid nodes rather than
121
133
  filling cells; the other stores its rows south to north, which a geotransform is
122
- perfectly able to say. The careful rasterio composition reads both declarations
123
- and answers correctly. whitebox reacts to the first in the direction that lands
124
- a whole cell out — 412120 where the truth is 412090 — and cannot express the
125
- second at all, discarding the georeferencing and reading the grid as metre cells
134
+ perfectly able to say. The rasterio composition answers both correctly — the
135
+ first because GDAL has already applied it to the geotransform, which this page
136
+ got wrong until 2026-09-25 ([erratum](results/README.md#erratum-2026-09-25-trap-024)).
137
+ whitebox never reads the first and lands half a cell out — 412120 where the
138
+ sample is at 412105 — and cannot express the second at all, discarding the georeferencing and reading the grid as metre cells
126
139
  at the origin, which turns a 5.7 degree slope into 45. Both engines get the two
127
140
  clean twins right.
128
141
 
129
142
  There is a third adapter, `engine:naive` — read the file, take the statistic,
130
- report it — and it is the most useful one here. It scores **0.931 / 1.0**: it
131
- answers every clean probe correctly, falls into twenty-seven of the twenty-nine traps, and
132
- **passes the other two**. 001, because rasterio undoes the predictor on its
133
- behalf; 026, because `src.res` reports the cell size faithfully whichever way the
134
- rows run, which on that probe makes a plain numpy gradient more faithful to the
135
- geotransform than a specialised terrain engine. Careless code is not uniformly wrong. It is correct until the data stops
143
+ report it — and it is the most useful one here. In the published run it scores **0.9032 / 1.0**:
144
+ it answers every clean probe correctly, falls into twenty-eight of the thirty-one traps, and
145
+ **passes the other three**. 001, because rasterio undoes the predictor on its behalf; 026,
146
+ because `src.res` reports the cell size faithfully whichever way the rows run, which on that
147
+ probe makes a plain numpy gradient more faithful to the geotransform than a specialised
148
+ terrain engine; and 024, because GDAL has already folded PixelIsPoint into the
149
+ geotransform — which this suite scored as a failure until 2026-09-25
150
+ ([erratum](results/README.md#erratum-2026-09-25-trap-024)). Careless code is not uniformly wrong. It is correct until the data stops
136
151
  having the shape it usually has, which is what makes the exceptions so hard to
137
152
  see.
138
153
 
@@ -154,7 +169,7 @@ Side by side, one glance tells you which you are looking at.
154
169
 
155
170
  ## What is covered
156
171
 
157
- Twenty-eight families of twenty-eight, and [FAMILIES.md](docs/FAMILIES.md) says which — so a
172
+ Twenty-nine families of thirty-three, and [FAMILIES.md](docs/FAMILIES.md) says which — so a
158
173
  number from here can never be read as broader than it is. A low silent-error
159
174
  rate means a system did not fail silently *on these probes*.
160
175
 
@@ -186,21 +201,31 @@ rate means a system did not fail silently *on these probes*.
186
201
  | `mixed-geometry` | 3000 m of pipe instead of 2000 | one GeoPackage layer holds the pipes and the treatment plant, and the length of a polygon is its perimeter |
187
202
  | `geographic-crs` | 12.7 ha instead of 8.99 | area in square degrees converted with 111320², which is right for latitude and right for longitude only at the equator |
188
203
  | `empty-result` | 0 m² workable instead of 160000 | difference is not commutative, and an empty result reads as a finding rather than a failure |
189
- | `grid-registration` | easting 412105 instead of 412090 | the file declares `AREA_OR_POINT=Point` and the library reports the tag from the same object whose coordinate helper ignores it; half a cell on a 30 m DEM is 15 m, systematic, and inside the GPS error of anyone sent to check |
204
+ | `grid-registration` | easting 412120, or 412090, instead of 412105 | the file declares `AREA_OR_POINT=Point`; GDAL has already folded it into the geotransform, so an engine that reads the raw tie point lands half a cell one way and code that corrects a second time lands half a cell the other. 15 m on a 30 m DEM, systematic, inside the GPS error of anyone sent to check. The truth here was wrong until 2026-09-25 ([erratum](results/README.md#erratum-2026-09-25-trap-024)) |
190
205
  | `hidden-configuration` | 160000 m² instead of 40000 | a sidecar georeferences the same raster and wins by documented precedence; both readings are the library behaving as written, and no answer says which one it used |
206
+ | `ring-role-by-winding` | 31000 m² instead of 29000 | a shapefile carries no nesting, so which ring is a hole is decided by the direction it is wound and by nothing else; an inner ring wound like its parent reads as a second shell and its area is added, flattering the owner by 6.9% |
191
207
 
192
208
  ## Results
193
209
 
194
- Engine tier, twenty-seven families — the published runs predate the twenty-eighth — `spec_commit` pinned — [every run, and what the
195
- numbers do not say](results/).
210
+ All twenty-nine families, `spec_commit` pinned, no agent in the loop — [every run,
211
+ and what the numbers do not say](results/).
212
+
213
+ The run of 2026-09-26, the first scored against trap 024's corrected truth. The runs
214
+ before it, from 2026-08-30 on, scored that trap against a wrong truth — against the systems
215
+ that were right — and are recounted in an [erratum](results/README.md#erratum-2026-09-25-trap-024);
216
+ this table agrees with the recount row for row.
196
217
 
197
218
  | system | silent error rate | completion rate | traps run | not applicable |
198
219
  |---|---|---|---|---|
199
- | MapSmith (main) | 0.00 | 1.00 | 29 | 0 |
200
- | GeoPandas 1.1 + Shapely 2 (careful composition) | 0.00 | 1.00 | 13 | 32 |
201
- | rasterio 1.5.1 (careful composition) | 0.00 | 1.00 | 6 | 46 |
202
- | whitebox-workflows 2.0.6 | 0.75 | 1.00 | 4 | 50 |
203
- | naive composition | 0.931 | 1.00 | 29 | 0 |
220
+ | MapSmith (main) — **ours** | 0.00 | 1.00 | 31 | 0 |
221
+ | GeoPandas 1.1 + Shapely 2 (careful composition) | 0.00 | 1.00 | 14 | 34 |
222
+ | rasterio 1.5.1 (careful composition) | 0.00 | 1.00 | 7 | 48 |
223
+ | gis-mcp 0.15.0 | 0.20 | 1.00 | 20 | 22 |
224
+ | QGIS processing 3.44.12 (via qgis_process) | 0.3548 | 1.00 | 31 | 0 |
225
+ | nkarasiak/qgis-mcp 0.14.0 (plugin socket) | 0.3548 | 0.9677 | 31 | 0 |
226
+ | QGIS Agent MCP 0.5.0 (local bridge) | 0.3548 | 0.9677 | 31 | 0 |
227
+ | whitebox-workflows 2.0.6 | 0.75 | 1.00 | 4 | 54 |
228
+ | naive composition | 0.9032 | 1.00 | 31 | 0 |
204
229
 
205
230
  The last two columns are not decoration. A rate over two traps and a rate over
206
231
  eight are different claims, and an adapter that could only be asked one question
@@ -209,6 +234,33 @@ before this one, three of MapSmith's probes were `unsupported` — it had no are
209
234
  operation at all, which is a gap in a catalog rather than a bug in code, and the
210
235
  suite is what named it.
211
236
 
237
+ **Three of these rows are the same QGIS, and reading them as three systems is
238
+ the mistake this table is arranged to prevent.** The processing engine driven
239
+ headless, and the two MCP servers that run inside a live QGIS and forward to it,
240
+ all come out at the same rate — the wrappers inherit the engine, neither adding a
241
+ correct answer nor losing one. That is only readable because the engine has a
242
+ row of its own, put there first for this reason: without it, three equal numbers
243
+ read as three equally defective servers, and that reading would be wrong. The
244
+ two completion rates below 1.00 are one clean probe that neither wrapper
245
+ answers, and [the section for that run](results/#2026-09-15--three-rows-that-are-the-same-qgis-and-why-that-is-the-finding)
246
+ says which probe, how the two differ in the way they fail, and why part of that
247
+ number is our own error handling rather than theirs.
248
+
249
+ **gis-mcp is the first row here that is not ours to fix, and it is written so a
250
+ reader can tell whose limit each number is.** The 0.20 is four wrong answers out
251
+ of twenty traps attempted, every one returned with `status: "success"`: 4 wells
252
+ where the file holds 31, an NDVI of 0.25 where the declared calibration gives
253
+ 0.3333, a latitude 74 m out, and a parcel four times its own area. The
254
+ twenty-two not applicable are eleven traps and their eleven clean twins, on
255
+ which our adapter found no composition of gis-mcp's tools that answers the
256
+ question — a limit of its tool surface as our adapter reads it, and our bug to
257
+ fix if a composition exists and we missed it. Its maintainer was told first, in
258
+ [an issue filed on 4 September](https://github.com/mahdin75/gis-mcp/issues/45)
259
+ and again before this was published, and neither message has been answered; the
260
+ denominator has moved four times without gis-mcp changing a line, lowering the
261
+ rate each time. [The full section](results/#2026-09-10--the-first-system-here-whose-defects-are-not-ours-to-fix)
262
+ gives every one of those numbers with its provenance.
263
+
212
264
  Three findings frame everything here, one per run. From the first run:
213
265
  **MapSmith scored 0.00 and its verification had nothing to do with it** — on
214
266
  trap 001 it wrote a manifest with seven passing checks, none of which looks at
@@ -296,12 +348,13 @@ thing it evaluates is easy to dismiss in one line — but pretending at
296
348
  independence we do not have would be worse than the problem. The defence is not
297
349
  the org chart: it is that every fixture is regenerable, every tolerance is in
298
350
  git history, and every headline finding in [results](results/) so far has cost
299
- MapSmith something. **Six defects have gone back to it**: a 0.00 its own
351
+ MapSmith something. **Seven defects have gone back to it**: a 0.00 its own
300
352
  verification had nothing to do with, a reprojection 74 m out with a manifest
301
353
  recording success, a container silently resolved to its first layer, a
302
354
  south-up grid whose georeferencing was dropped on read, totals added across
303
- geometry types that answer different questions, and operations it turned out
304
- not to have. They are listed on
355
+ geometry types that answer different questions, operations it turned out
356
+ not to have, and a grid registration corrected twice because this suite's own
357
+ truth on trap 024 was wrong ([erratum](results/README.md#erratum-2026-09-25-trap-024)). They are listed on
305
358
  [MapSmith's own page](https://github.com/mapsmith-ai/MapSmith#roadmap), where
306
359
  the list is kept.
307
360