mapsmith 0.6.0__tar.gz → 0.7.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.
- {mapsmith-0.6.0 → mapsmith-0.7.0}/.zenodo.json +1 -1
- {mapsmith-0.6.0 → mapsmith-0.7.0}/CHANGELOG.md +182 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/CITATION.cff +2 -2
- {mapsmith-0.6.0 → mapsmith-0.7.0}/PKG-INFO +75 -52
- {mapsmith-0.6.0 → mapsmith-0.7.0}/README.md +74 -51
- {mapsmith-0.6.0 → mapsmith-0.7.0}/docs/argleton-run.json +14 -11
- {mapsmith-0.6.0 → mapsmith-0.7.0}/docs/benchmarks.md +19 -7
- {mapsmith-0.6.0 → mapsmith-0.7.0}/docs/catalog-entry-spec.md +6 -6
- {mapsmith-0.6.0 → mapsmith-0.7.0}/docs/manifest-vocabulary.md +10 -6
- {mapsmith-0.6.0 → mapsmith-0.7.0}/examples/01_verified_geoprocessing.ipynb +25 -25
- {mapsmith-0.6.0 → mapsmith-0.7.0}/examples/02_terrain_hydrology.ipynb +37 -37
- {mapsmith-0.6.0 → mapsmith-0.7.0}/examples/03_validated_plans.ipynb +23 -23
- mapsmith-0.7.0/examples/04_copernicus_terrain_vegetation.ipynb +522 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/examples/README.md +12 -3
- mapsmith-0.7.0/examples/fixtures/COPERNICUS-NOTICE.md +35 -0
- mapsmith-0.7.0/examples/fixtures/fetch_copernicus.py +123 -0
- mapsmith-0.7.0/examples/fixtures/monte_baldo_dem.tif +0 -0
- mapsmith-0.7.0/examples/fixtures/monte_baldo_s2.tif +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/pyproject.toml +1 -1
- {mapsmith-0.6.0 → mapsmith-0.7.0}/server.json +3 -3
- {mapsmith-0.6.0 → mapsmith-0.7.0}/site/build.py +54 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/site/index.template.html +12 -10
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/__init__.py +1 -1
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/antimeridian.py +109 -19
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/catalog.py +94 -29
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/engines/network.py +6 -6
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/engines/raster.py +215 -37
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/engines/sampling.py +414 -43
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/engines/vector.py +13 -2
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/engines/whitebox_engine.py +95 -38
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/gdal_policy.py +17 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/grid.py +71 -89
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/plans/registry.py +5 -2
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/provenance.py +36 -8
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/server.py +14 -1
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/data/manifest-v1.schema.json +29 -4
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/data/manifest_spec_validator.py +39 -1
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_failure_manifest.py +4 -2
- mapsmith-0.7.0/tests/test_grid_registration.py +530 -0
- mapsmith-0.7.0/tests/test_raster.py +358 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_redaction.py +56 -54
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_sampling.py +272 -4
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_showcase.py +53 -1
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_stacks.py +3 -3
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_summarize_points_in_polygons.py +71 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_verify.py +39 -6
- mapsmith-0.6.0/tests/test_grid_registration.py +0 -449
- mapsmith-0.6.0/tests/test_raster.py +0 -94
- {mapsmith-0.6.0 → mapsmith-0.7.0}/.dockerignore +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/.gitignore +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/CLAUDE.md +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/CONTRIBUTING.md +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/Dockerfile +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/LICENSE +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/MANIFESTO.md +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/SECURITY.md +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/TRADEMARKS.md +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/docker-compose.yml +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/examples/fixtures/mount_st_helens_dem.tif +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/funding.json +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/glama.json +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/schema/operation.schema.json +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/datum.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/discovery_log.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/engines/__init__.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/engines/dispatch.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/engines/duckdb_engine.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/engines/esri.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/engines/geodesy.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/engines/linework.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/engines/sedona_engine.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/engines/spatial_stats.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/engines/summaries.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/jobs.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/lineage.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/plans/__init__.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/plans/executor.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/plans/models.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/plans/validator.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/preview.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/readers.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/retrieval.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/sql_policy.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/stacks.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/ui.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/verify.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/src/mapsmith/workspace.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/conftest.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/data/discovery_queries.json +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_ambiguous_layer.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_antimeridian.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_band_math.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_catalog.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_catalog_applicability.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_catalog_entry_spec.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_catalog_retrieval.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_centroid_convert.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_clip_reclassify_raster.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_contours_and_cost.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_dashboard.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_datum.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_describe_raster.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_discovery_contract.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_discovery_log.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_discovery_report.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_duckdb_sandbox.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_engines.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_environment.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_gdal_policy.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_geodesy.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_geoparquet2.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_lineage.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_linework.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_measure_area.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_merge_simplify.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_nearest_explode.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_network.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_overlay_dissolve.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_path_containment.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_plans.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_preview.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_published_figures.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_raster_reproject_bands.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_resample_raster.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_retrieval.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_retrieval_at_scale.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_retrieval_degradation.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_select_and_extract.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_smoke.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_south_up_and_mixed.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_spatial_stats.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_sql_axis_order.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_sql_credentials.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_summaries.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_terrain_derivatives.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_tier_a_operations.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_ui.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_verification_status.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_verify_repair.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_voronoi.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_whitebox.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_whitebox_derivatives.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_whitebox_encoding.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_whitebox_geographic_refusal.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_worked_example.py +0 -0
- {mapsmith-0.6.0 → mapsmith-0.7.0}/tests/test_workspace.py +0 -0
|
@@ -8,6 +8,188 @@ All notable changes to MapSmith are documented here, in the format of
|
|
|
8
8
|
|
|
9
9
|
Nothing yet.
|
|
10
10
|
|
|
11
|
+
## [0.7.0] - 2026-09-26
|
|
12
|
+
|
|
13
|
+
**This release changes answers earlier releases gave, and that comes first.**
|
|
14
|
+
From 0.4.0 to 0.6.1 every position MapSmith read from a point-registered raster
|
|
15
|
+
(`AREA_OR_POINT=Point` — the USGS elevation products and the Copernicus DEM)
|
|
16
|
+
was half a cell north-west of the sample: GDAL already corrects for the tag, and
|
|
17
|
+
MapSmith corrected a second time. The same premise sat in the correctness suite
|
|
18
|
+
MapSmith is graded by, which scored the wrong answer as a pass; it has published
|
|
19
|
+
an [erratum](https://github.com/argleton/argleton/blob/main/results/README.md#erratum-2026-09-25-trap-024).
|
|
20
|
+
Terrain operations now accept point-registered DEMs, which they refused
|
|
21
|
+
outright. Two capabilities arrive on existing tools — weighted zonal statistics
|
|
22
|
+
and the gradient along a line — with a Copernicus notebook. No tool was added.
|
|
23
|
+
Two records change shape, both below: `elevation_profile` across two CRSs uses
|
|
24
|
+
the specification's `source_crs`/`target_crs`, and terrain operations record
|
|
25
|
+
the raster registration in `crs_decisions`.
|
|
26
|
+
|
|
27
|
+
Records declare `spec_version` `1.0.0-draft.8`, as in 0.6.1.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- **A Copernicus notebook.** `examples/04_copernicus_terrain_vegetation.ipynb`,
|
|
32
|
+
on Monte Baldo: a Copernicus DEM in degrees refused for slope and reprojected,
|
|
33
|
+
a Sentinel-2 NDVI, and the treeline read off both. Two clips ship in
|
|
34
|
+
`examples/fixtures/` under their own licences, with the script that rebuilds
|
|
35
|
+
them. It found both fixes above, and one fact about the data: for the item it
|
|
36
|
+
uses, the Sentinel-2 catalogue declares a reflectance offset of -0.1 that the
|
|
37
|
+
pixels already contain — deep water would read -7% — so the clip declares the
|
|
38
|
+
scale alone, and the script re-checks it every time it runs.
|
|
39
|
+
|
|
40
|
+
- **Weighted zonal statistics.** `zonal_statistics` takes `weights_path`, a
|
|
41
|
+
raster of weights, and `weighted_mean`, `weighted_sum`, `weighted_stdev`,
|
|
42
|
+
`weighted_variance` and `weighted_frac`: the mean heat of a district weighted
|
|
43
|
+
by the population living in each cell, which used to take three operations
|
|
44
|
+
and a division and is a different number from the plain mean wherever people
|
|
45
|
+
are not spread evenly. Both rules were measured on the engine first.
|
|
46
|
+
|
|
47
|
+
One is in the record: a cell with a value and no weight -- nodata or NaN --
|
|
48
|
+
counts with weight 0, because exactextract's own default turns the zone's
|
|
49
|
+
weighted statistics into NaN for a single missing weight. The record carries
|
|
50
|
+
`weight_of_a_cell_with_no_weight: 0.0` and the weights by name
|
|
51
|
+
(`weights_path`) as well as in `inputs[]`, and a non-critical check,
|
|
52
|
+
`x-mapsmith:every_valued_cell_has_a_weight`, names the zones where it
|
|
53
|
+
happened.
|
|
54
|
+
|
|
55
|
+
The other is a refusal, so a record exists only when it held: the weights
|
|
56
|
+
must sit on the value raster's own grid -- same CRS, cells (compared relative
|
|
57
|
+
to the cell size) and registration -- because exactextract accepts a coarser
|
|
58
|
+
grid by repeating each coarse cell whole in every fine one, which inflates a
|
|
59
|
+
weighted sum of counts, and never compares the two coordinate systems. A
|
|
60
|
+
weights raster off the grid, with two bands, or with a negative weight inside
|
|
61
|
+
a zone is refused with how to align it; a negative weight outside every zone
|
|
62
|
+
changes no number and is not.
|
|
63
|
+
|
|
64
|
+
With two rasters in one record, each one's georeferencing facts stay with
|
|
65
|
+
it: the top-level `environment` describes `inputs[0]`, and the weights' are
|
|
66
|
+
on their own entry under `x-mapsmith:environment`. Records of operations
|
|
67
|
+
that read one raster are unchanged. Reached through the same tool; the tool
|
|
68
|
+
count is unchanged.
|
|
69
|
+
|
|
70
|
+
- **The gradient along a line.** `elevation_profile` takes `grade_base_length`
|
|
71
|
+
and, optionally, `grade_threshold_percent`: every point carries
|
|
72
|
+
`grade_percent`, the rise over the window of that length starting there, and
|
|
73
|
+
the result gives per line the steepest window and where it starts, the total
|
|
74
|
+
ascent and descent, and the stretches above the threshold. It closes four
|
|
75
|
+
railway requests that each took a plan -- "the steepest section in percent",
|
|
76
|
+
"the maximum gradient over any 100 m", "does any part exceed 2.5%" -- and
|
|
77
|
+
three traps are decided rather than defaulted: this is not `slope`, which is
|
|
78
|
+
the ground's steepest direction and on a track crossing a hillside at 45
|
|
79
|
+
degrees says 2% where the track climbs 1.41%; the window slides by the
|
|
80
|
+
spacing, so it answers "any 100 m stretch" and not "every 100 m from the
|
|
81
|
+
start"; and the base length has no default and must be a whole number of
|
|
82
|
+
steps. A window never crosses the gap between two parts of a multi-part line
|
|
83
|
+
that do not touch (each point carries `run_index`), nor a point the raster
|
|
84
|
+
could not read; a stretch is one direction of travel, so a climb and the
|
|
85
|
+
descent after it are two. A line whose unit is not the metre needs
|
|
86
|
+
`grade_height_unit`, because the rise comes from the raster's values, which
|
|
87
|
+
state no unit, and metres over US survey feet is 3.28 times too steep. A check
|
|
88
|
+
recomputes every stored grade from the profile as written and fails on a
|
|
89
|
+
grade missing where a window fits, with the count in its detail.
|
|
90
|
+
The new search phrasings moved discovery figures the right way: words alone
|
|
91
|
+
under BM25 at 76 entries from 50% to 55%.
|
|
92
|
+
|
|
93
|
+
### Fixed
|
|
94
|
+
|
|
95
|
+
- **Every position read from a point-registered raster was half a cell off,
|
|
96
|
+
since 0.4.0.** On a file declaring `AREA_OR_POINT=Point` MapSmith moved each
|
|
97
|
+
sample half a cell north-west of where GDAL puts it: sampling,
|
|
98
|
+
`elevation_profile`, `line_of_sight`, `locate_extreme_cell`, `least_cost_path`,
|
|
99
|
+
and the zones of `zonal_statistics`, which were shifted for the coverage
|
|
100
|
+
computation. The premise was that GDAL reports the tag and leaves the
|
|
101
|
+
geotransform alone. It does the opposite — since RFC 33 the GTiff driver moves
|
|
102
|
+
a PixelIsPoint tie point half a cell on write and on read, so its geotransform
|
|
103
|
+
already centres each cell on its sample — and the correction was made twice.
|
|
104
|
+
Found by a Copernicus DEM, whose samples fall on whole arc-seconds by its own
|
|
105
|
+
documentation: 10.8 by GDAL, 10.79986 by MapSmith. Positions now come from
|
|
106
|
+
GDAL's geotransform whatever the tag says; the tag is still recorded, because
|
|
107
|
+
it says what a value represents. The same premise was in Argleton trap 024,
|
|
108
|
+
which scored MapSmith's wrong answer as correct for 26 days; the suite has
|
|
109
|
+
published an [erratum](https://github.com/argleton/argleton/blob/main/results/README.md#erratum-2026-09-25-trap-024).
|
|
110
|
+
A weights raster is no longer refused for a registration different from the
|
|
111
|
+
values': on the same geotransform the samples are in the same places. And the
|
|
112
|
+
fix no longer depends on the environment: `GTIFF_POINT_GEO_IGNORE=TRUE`, which
|
|
113
|
+
reverts GDAL to its pre-2010 reading, moved every answer half a cell back with
|
|
114
|
+
nothing in the record to say why, so MapSmith now pins it to `FALSE` on import,
|
|
115
|
+
whether or not remote paths are allowed — which also overrides an operator's
|
|
116
|
+
setting in a process that imports `mapsmith` as a library, deliberately.
|
|
117
|
+
|
|
118
|
+
- **The terrain operations refused every point-registered DEM, the Copernicus
|
|
119
|
+
DEM included.** The engine reads the stored tie point as a cell corner, and
|
|
120
|
+
the guard that compares its grid with GDAL's caught the half cell and refused,
|
|
121
|
+
so the numbers were never wrong and twelve operations were unusable on the
|
|
122
|
+
most used global DEM (the eleven that write a raster, and `contour_lines`). The engine now gets a copy declared area-registered on
|
|
123
|
+
GDAL's own geotransform — the same pattern as the TIFF predictor, disclosed in
|
|
124
|
+
the manifest — and the output gets the input's registration back. Their
|
|
125
|
+
manifests record the registration in `crs_decisions`, as the raster writers
|
|
126
|
+
already did, and say when MapSmith retagged an output after the engine wrote
|
|
127
|
+
it, since those bytes are no longer the engine's alone.
|
|
128
|
+
`contour_lines` loses a branch for point-registered DEMs that corrected half a
|
|
129
|
+
cell the wrong way and could not be reached.
|
|
130
|
+
|
|
131
|
+
- **`elevation_profile` measured the spacing in the DEM's units, and on a DEM
|
|
132
|
+
in degrees a 1000 m line came back as one point.** The line was reprojected
|
|
133
|
+
to the raster's CRS before its positions were computed, so `spacing=100`
|
|
134
|
+
meant 100 degrees, and the only trace was a GeoPandas warning on the console.
|
|
135
|
+
Positions are now measured along the line in its own projected CRS -- a
|
|
136
|
+
geographic line was already refused -- and only the sample points go to the
|
|
137
|
+
raster's CRS to be read. **The output is now in the line's CRS**: when the two
|
|
138
|
+
differed it used to be in the raster's, and a plan step reading it must now
|
|
139
|
+
expect the line's (the plan validator does). The record says what was
|
|
140
|
+
transformed in the specification's own keys: `source_crs` the line's,
|
|
141
|
+
`target_crs` the raster's, and the `transformation` the sample points took to
|
|
142
|
+
be read, while `output.crs` says where the result is. It used to list the line
|
|
143
|
+
under `x-mapsmith:inputs_reprojected` from its own CRS, which that key's
|
|
144
|
+
definition makes a contradiction. When line and DEM share a CRS nothing
|
|
145
|
+
changes. Found while building a gradient on top of it.
|
|
146
|
+
|
|
147
|
+
- **`elevation_profile` stopped short of the far end of a line.** A line whose
|
|
148
|
+
length is not a whole number of steps ended on the last whole step: 15 m at a
|
|
149
|
+
step of 4 ended at 12, and a summit in the last 3 m was not in the profile,
|
|
150
|
+
while the docstring and the name of the test said both ends were included --
|
|
151
|
+
and the test asserted the opposite. The far end is now a last, shorter step,
|
|
152
|
+
and the stepping check requires it.
|
|
153
|
+
|
|
154
|
+
## [0.6.1] - 2026-09-25
|
|
155
|
+
|
|
156
|
+
A small release on the day of 0.6.0. It moves no manifest key and changes no
|
|
157
|
+
answer that 0.6.0 got right: it stops a refusal 0.6.0 introduced from firing on
|
|
158
|
+
a layer written in 0..360 longitudes, gives two refusals the right way out, and
|
|
159
|
+
declares the specification's current draft.
|
|
160
|
+
|
|
161
|
+
### Changed
|
|
162
|
+
|
|
163
|
+
- **Records declare `spec_version` `1.0.0-draft.8`.** Two drafts in one day,
|
|
164
|
+
both narrowings of where a producer may add a key: draft.7 requires every
|
|
165
|
+
key of `crs_decisions` the specification does not define to be named
|
|
166
|
+
`x-<producer>:<name>`, which it had left to one reading of an ambiguous
|
|
167
|
+
sentence, and draft.8 carries the rule inside `transformation`,
|
|
168
|
+
`round_trip` and `repairs[]`. MapSmith already named every one of them that
|
|
169
|
+
way, so no key moves: a reader keying on the label sees draft.8, a reader
|
|
170
|
+
keying on fields sees nothing change. The vendored schema and validator are
|
|
171
|
+
draft.8's, and the conformance sweep validates every writer's record
|
|
172
|
+
against them.
|
|
173
|
+
|
|
174
|
+
### Fixed
|
|
175
|
+
|
|
176
|
+
- **A layer written in 0..360 longitudes had its seam in the wrong place.**
|
|
177
|
+
The antimeridian refusal of 0.6.0 took the edge of the plane to be -180/180,
|
|
178
|
+
so the world written as `box(0, -90, 360, 90)` was refused, the way 0.6.0's
|
|
179
|
+
own review had found Antarctica refused in -180..180. For such a layer the
|
|
180
|
+
edge is 0/360, and the ring that really is drawn naively crosses the prime
|
|
181
|
+
meridian: the refusal now says so and tells its author to split there, where
|
|
182
|
+
it used to send them to 180. A layer is read as 0..360 when it has no
|
|
183
|
+
negative longitude and some beyond 180 -- not whenever one vertex passes
|
|
184
|
+
180, which the first version of this fix did, and which refused the world
|
|
185
|
+
beside a polygon overshooting 180 by 1e-7. Edges along either pair of seams
|
|
186
|
+
are exempt in every layer.
|
|
187
|
+
- **"No UTM zone" said the data was centred on the antimeridian, whatever the
|
|
188
|
+
data, and offered no way out.** The realistic cause is latitude — UTM stops
|
|
189
|
+
at 84N and 80S — and the message now says that and names a polar CRS to use
|
|
190
|
+
(UPS, or a polar stereographic), for data that crosses 180 and for data that
|
|
191
|
+
does not.
|
|
192
|
+
|
|
11
193
|
## [0.6.0] - 2026-09-25
|
|
12
194
|
|
|
13
195
|
The reason to upgrade is in **Fixed**: five operations stop reading a zone drawn
|
|
@@ -12,8 +12,8 @@ identifiers:
|
|
|
12
12
|
value: "10.5281/zenodo.22213091"
|
|
13
13
|
description: "Concept DOI — always resolves to the latest release"
|
|
14
14
|
license: AGPL-3.0-or-later
|
|
15
|
-
version: "0.
|
|
16
|
-
date-released: "2026-09-
|
|
15
|
+
version: "0.7.0"
|
|
16
|
+
date-released: "2026-09-26"
|
|
17
17
|
keywords:
|
|
18
18
|
- GIS
|
|
19
19
|
- geospatial
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: mapsmith
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Professional-grade GIS geoprocessing over MCP, with verifiable provenance
|
|
5
5
|
Project-URL: Homepage, https://github.com/mapsmith-ai/MapSmith
|
|
6
6
|
Project-URL: Repository, https://github.com/mapsmith-ai/MapSmith
|
|
@@ -87,7 +87,7 @@ MapSmith's private output: JSON Schema, a toolchain-free validator, a conformanc
|
|
|
87
87
|
hundred-line emitter that never imports MapSmith. Records carry `spec_version`, and CI validates
|
|
88
88
|
real MapSmith output against the spec's own validator. The specification is archived and citable
|
|
89
89
|
as [10.5281/zenodo.22205213](https://doi.org/10.5281/zenodo.22205213), a concept DOI that
|
|
90
|
-
resolves to the latest *archived* draft. These records declare `1.0.0-draft.
|
|
90
|
+
resolves to the latest *archived* draft. These records declare `1.0.0-draft.8`; if the DOI shows
|
|
91
91
|
an earlier one, the archive has not caught up, and the
|
|
92
92
|
[repository](https://github.com/mapsmith-ai/manifest-spec) holds the text they are written against. The names MapSmith puts
|
|
93
93
|
in a record beyond the ones the specification defines — every extension check name, and every
|
|
@@ -97,9 +97,11 @@ generated from the source rather than maintained by hand.
|
|
|
97
97
|
|
|
98
98
|
Evidence before promises. A correctness suite in its own organisation,
|
|
99
99
|
[**Argleton**](https://argleton.org), grades MapSmith on thirty-one traps whose answers are
|
|
100
|
-
computed on paper before any system runs: **0.
|
|
101
|
-
0.
|
|
102
|
-
|
|
100
|
+
computed on paper before any system runs: **0.03 silent errors — one in thirty-one, nothing
|
|
101
|
+
skipped** — against 0.9032 for the obvious way of writing the same code. That one was published
|
|
102
|
+
as a pass: the trap's own truth was wrong in MapSmith's favour for 26 days, the error is ours
|
|
103
|
+
twice over, and the [erratum](https://github.com/argleton/argleton/blob/main/results/README.md#erratum-2026-09-25-trap-024) says so; the fix is on `main`. Getting here cost
|
|
104
|
+
seven defects the suite sent back, and they are listed. Alongside it: an [A/B on GABench](docs/benchmarks.md) whose
|
|
103
105
|
headline is a null result — with the analysis that took our own positive number apart —
|
|
104
106
|
[notebooks](examples/) on a real USGS DEM of Mount St. Helens, an
|
|
105
107
|
[in-chat map panel](#see-results-inside-the-chat) that shows the verification status of
|
|
@@ -132,15 +134,15 @@ flowchart TB
|
|
|
132
134
|
ASK --> PLAN{{"plan validated<br/>before anything runs"}}
|
|
133
135
|
PLAN -. "rejected: FORWARD_REFERENCE" .-> BAD["'mask_path' references '$buffer' which runs later — move step 'buffer' before 'near'"]
|
|
134
136
|
BAD:::bad
|
|
135
|
-
BUFFER["<b>buffer_layer</b><br/>76 operations →
|
|
137
|
+
BUFFER["<b>buffer_layer</b><br/>76 operations → 30 candidates → chosen<br/>CRS EPSG:32610<br/>9/9 checks"]
|
|
136
138
|
PLAN --> BUFFER
|
|
137
139
|
NEAR["<b>clip_layer</b><br/>76 operations → 15 candidates → chosen<br/>CRS EPSG:4326<br/>12/12 checks"]
|
|
138
140
|
BUFFER --> NEAR
|
|
139
141
|
HEIGHT["<b>zonal_statistics</b><br/>76 operations → 4 candidates → chosen<br/>CRS EPSG:4326<br/>7/7 checks"]
|
|
140
142
|
NEAR --> HEIGHT
|
|
141
|
-
AREA["<b>measure_area</b><br/>76 operations →
|
|
143
|
+
AREA["<b>measure_area</b><br/>76 operations → 30 candidates → chosen<br/>CRS WGS 84 (ellipsoidal)<br/>10/10 checks"]
|
|
142
144
|
HEIGHT --> AREA
|
|
143
|
-
FILTER["<b>select_features</b><br/>76 operations →
|
|
145
|
+
FILTER["<b>select_features</b><br/>76 operations → 30 candidates → chosen<br/>CRS EPSG:4326<br/>10/10 checks"]
|
|
144
146
|
AREA --> FILTER
|
|
145
147
|
OUT[["3 parcels, each with elevation and ground area"]]
|
|
146
148
|
FILTER --> OUT
|
|
@@ -149,11 +151,11 @@ flowchart TB
|
|
|
149
151
|
|
|
150
152
|
| what the agent asks for | it declares | candidates | picked | at position |
|
|
151
153
|
|---|---|---|---|---|
|
|
152
|
-
| “everything within one and a half kilometres of the river” | vector, dataset:vector, 1 dataset(s) | **
|
|
154
|
+
| “everything within one and a half kilometres of the river” | vector, dataset:vector, 1 dataset(s) | **30** of 76 | `buffer_layer` | 2 |
|
|
153
155
|
| “keep only the parcels that fall inside that strip” | vector, dataset:vector, 2 dataset(s) | **15** of 76 | `clip_layer` | 1 |
|
|
154
156
|
| “how high is the ground under each of these parcels” | raster, dataset:vector, 2 dataset(s) | **4** of 76 | `zonal_statistics` | 3 |
|
|
155
|
-
| “how big is each one on the ground” | vector, dataset:vector, 1 dataset(s) | **
|
|
156
|
-
| “drop the ones where the ground is above 120 metres” | vector, dataset:vector, 1 dataset(s) | **
|
|
157
|
+
| “how big is each one on the ground” | vector, dataset:vector, 1 dataset(s) | **30** of 76 | `measure_area` | 1 |
|
|
158
|
+
| “drop the ones where the ground is above 120 metres” | vector, dataset:vector, 1 dataset(s) | **30** of 76 | `select_features` | 2 |
|
|
157
159
|
|
|
158
160
|
| step | operation | arguments that mattered | CRS decision, recorded | checks |
|
|
159
161
|
|---|---|---|---|---|
|
|
@@ -263,17 +265,20 @@ or from a terminal: `code --add-mcp '{"name":"mapsmith","command":"uvx","args":[
|
|
|
263
265
|
To check it runs before wiring a client, `uvx mapsmith` starts the server on stdio
|
|
264
266
|
(Ctrl-C to quit) — it speaks MCP, not a CLI, so a silent prompt means it is working.
|
|
265
267
|
|
|
266
|
-
This page describes **0.
|
|
268
|
+
This page describes **0.7.0**, which is what that command installs. When `main` runs ahead of
|
|
267
269
|
the published artifact this paragraph says so and names the difference — a reader should never
|
|
268
|
-
have to find out by calling a tool that is not there.
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
`1.0.0-draft.
|
|
275
|
-
|
|
276
|
-
`
|
|
270
|
+
have to find out by calling a tool that is not there. **If you run 0.4.0 to 0.6.1, 0.7.0
|
|
271
|
+
changes answers you have**: every position read from a point-registered raster
|
|
272
|
+
(`AREA_OR_POINT=Point`, the USGS and Copernicus DEMs) was half a cell off, and the
|
|
273
|
+
[changelog](CHANGELOG.md) says which operations and why.
|
|
274
|
+
|
|
275
|
+
**If you read manifests, 0.7.0 renames no key**: records declare `spec_version`
|
|
276
|
+
`1.0.0-draft.8`, two drafts past 0.6.0's `draft.6`, and both drafts only narrowed where a
|
|
277
|
+
producer may add a key of its own — which MapSmith already did the narrower way. From 0.5.x,
|
|
278
|
+
0.6.0 renamed `x-mapsmith:round_trip` to `round_trip`; from 0.4.0, 0.5.0 had renamed eight
|
|
279
|
+
`crs_decisions` keys, the top-level `mapsmith_version` (read `producer.version`), two fields of
|
|
280
|
+
the round trip, two of `repairs[]` and `engine.geometry_library`. The changelog lists each with
|
|
281
|
+
what to read instead.
|
|
277
282
|
|
|
278
283
|
Then ask your agent things like:
|
|
279
284
|
|
|
@@ -299,8 +304,8 @@ for it:
|
|
|
299
304
|
|
|
300
305
|
```json
|
|
301
306
|
{
|
|
302
|
-
"spec_version": "1.0.0-draft.
|
|
303
|
-
"producer": {"name": "mapsmith", "version": "0.
|
|
307
|
+
"spec_version": "1.0.0-draft.8",
|
|
308
|
+
"producer": {"name": "mapsmith", "version": "0.7.0"},
|
|
304
309
|
"operation": "buffer_layer",
|
|
305
310
|
"parameters": {"distance_meters": 300.0},
|
|
306
311
|
"inputs": [{
|
|
@@ -450,10 +455,10 @@ was shown this catalog, because a model handed the entry writes a paraphrase of
|
|
|
450
455
|
|
|
451
456
|
| what the caller declares | candidates left | BM25, found@3 | embeddings, found@3 | **right answer in what comes back** |
|
|
452
457
|
|---|---|---|---|---|
|
|
453
|
-
| nothing — words alone | 76 | 29% |
|
|
454
|
-
| what data I have | 50 |
|
|
458
|
+
| nothing — words alone | 76 | 29% | 18% | 29% |
|
|
459
|
+
| what data I have | 50 | 32% | 21% | 33% |
|
|
455
460
|
| + what I want back | 31 | 45% | 40% | 53% |
|
|
456
|
-
| **+ how many datasets I have** | **
|
|
461
|
+
| **+ how many datasets I have** | **17** | **53%** | **49%** | **98%** |
|
|
457
462
|
|
|
458
463
|
**Two ranking columns, and that is a correction.** This table used to carry one,
|
|
459
464
|
computed with the default engine — which is the embedding one where its model
|
|
@@ -466,18 +471,22 @@ published under a sentence promising it could be checked.
|
|
|
466
471
|
The two also differ in a way worth seeing, and this page had it backwards
|
|
467
472
|
until 2026-08-30. It said the embedding engine overtakes BM25 once the facets
|
|
468
473
|
have narrowed. It does not overtake it anywhere: BM25 leads at every row of the
|
|
469
|
-
table above, by
|
|
470
|
-
declaration
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
+
table above, by eleven points on words alone and by four at the fullest
|
|
475
|
+
declaration, where the entries that survive are told apart by the words that
|
|
476
|
+
distinguish them — which is what `distinguishes` is for, and what an exact term
|
|
477
|
+
either matches or does not. The embedding engine earns its place on the
|
|
478
|
+
phrasings it has never seen, not on the ranking once the set is small. *(This
|
|
479
|
+
paragraph said until 2026-09-25 that the gap was seven to twelve points and
|
|
480
|
+
widest at the fullest declaration. It was the other way round with the figures
|
|
481
|
+
then published — narrowest there, at two — and nothing checked the sentence,
|
|
482
|
+
only the table beside it.)*
|
|
474
483
|
|
|
475
484
|
The last column is not an accuracy figure — it is a property, and the 98% rather than 100% is
|
|
476
485
|
worth a sentence. The narrowing never drops the right operation: that is asserted per entry and
|
|
477
486
|
holds for all 76. What the column measures is whether the surviving set was small enough to hand
|
|
478
487
|
over WHOLE, and for a handful of requests it still is not, so those fall back to a ranked
|
|
479
488
|
shortlist and the answer can be outside the top three. Ranking decides the order; it does not
|
|
480
|
-
decide membership; and the
|
|
489
|
+
decide membership; and the 2% is the gap between "cannot lose the answer" and "can show you all
|
|
481
490
|
of it".
|
|
482
491
|
|
|
483
492
|
**The third row is the scaling wall, and we hit it in one afternoon.** On 2026-08-29 the
|
|
@@ -508,10 +517,12 @@ of comparison this page exists to refuse.)
|
|
|
508
517
|
|
|
509
518
|
**And at 76 the cost showed where the new operation lives.** `summarize_points_in_polygons` takes two vector layers and returns one, which is the busiest corner of the facet space — `count_in_polygons`, `spatial_join` and `clip_layer` are its neighbours — so the bottom row's found@3 fell from 58% to 55% under BM25 while the average surviving set stayed at 16 and *delivered* held at 98%. The operation was added because «average pH by field block» took two calls to answer and so, to somebody searching, did not exist; three points of ranking at the fullest declaration is what that cost, and the guarantee that matters did not move.
|
|
510
519
|
|
|
520
|
+
**And when an existing operation gained an optional input, with no operation added.** `zonal_statistics` took a weights raster on 2026-09-25, so it reads two datasets or three, and an arity that varies is declared as none at all — the rule `run_sql` and `merge_layers` follow, because declaring 2 would hide the weighted form from a caller who correctly says they hold three. The price is that it now survives every arity: the average surviving set went from 16 to 17 and the bottom row's found@3 from 55% to 53%, with *delivered* still at 98%. A facet that stops discriminating for one entry costs every search a candidate.
|
|
521
|
+
|
|
511
522
|
That is the shape of the trade, and it says when the next facet is due. The figure to watch is
|
|
512
523
|
not found@3 — a ranker will always get worse as the catalogue grows, and it is a hint. It is the
|
|
513
524
|
**average** surviving set at the fullest declaration, the fourth column of that table:
|
|
514
|
-
9 at 51 operations, 14 at 61, 16 at 72, 16 at 74, 16 at 75,
|
|
525
|
+
9 at 51 operations, 14 at 61, 16 at 72, 16 at 74, 16 at 75, 17 at 76. When that crosses 30, delivery stops being a
|
|
515
526
|
property and starts being a ranking again, and the answer is another fact the caller already
|
|
516
527
|
knows, not a bigger threshold. (It said *median* until 2026-08-29, and published the mean:
|
|
517
528
|
the median at 76 is 15. The distribution is skewed — most requests leave a small set and a few
|
|
@@ -541,7 +552,7 @@ Three measurements say this is the right shape, and the third is the one that se
|
|
|
541
552
|
|
|
542
553
|
| | |
|
|
543
554
|
|---|---|
|
|
544
|
-
| our ranking puts the answer in the top three | **
|
|
555
|
+
| our ranking puts the answer in the top three | **53%** |
|
|
545
556
|
| a model handed the same candidates and asked to *choose* gets its first pick right | **69%** |
|
|
546
557
|
| the two labellers who wrote the ground truth agree **with each other** | **70%** |
|
|
547
558
|
|
|
@@ -572,7 +583,7 @@ against a human answer where there is one.
|
|
|
572
583
|
|
|
573
584
|
All three are over the same 118 requests, which matters: agreement measured over all 155 requests
|
|
574
585
|
in the file is 68%, and the difference is the 21 pairs where both labellers agreed a request was
|
|
575
|
-
unanswerable — true, and the easy half. Quoting that 68% beside a
|
|
586
|
+
unanswerable — true, and the easy half. Quoting that 68% beside a 53% computed over the 118 would
|
|
576
587
|
be comparing two populations, which this table did for half a day.
|
|
577
588
|
|
|
578
589
|
**The last row is a ceiling, not a baseline**, and the second row sits at it rather than below it.
|
|
@@ -594,7 +605,7 @@ numbers are reported as *agreement with model-written labels* and never as accur
|
|
|
594
605
|
used to be a hard filter like the others. It is not like the others: input kind and projected-CRS
|
|
595
606
|
are facts about the data in hand and output kind is what the caller wants, but *family* is a guess
|
|
596
607
|
about our taxonomy, which the caller cannot see. Measured, it removed six candidates out of
|
|
597
|
-
|
|
608
|
+
seventeen — and when the guess was wrong it removed the right operation, with no error, leaving a
|
|
598
609
|
confident answer assembled from neighbours. Every request in the independent set has 4.4 plausible
|
|
599
610
|
families. That is the silent-failure class [Argleton](https://argleton.org) measures in other
|
|
600
611
|
people's systems, sitting in our own discovery layer, so it now sorts: declaring the family lifts
|
|
@@ -631,7 +642,7 @@ catalog grows:
|
|
|
631
642
|
|---|---|---|
|
|
632
643
|
| 10 | 77% | 80% |
|
|
633
644
|
| 30 | 63% | 58% |
|
|
634
|
-
| 76 |
|
|
645
|
+
| 76 | 55% | 40% |
|
|
635
646
|
|
|
636
647
|
**This table used to say the opposite, and the reversal is the finding.** Published at 10/30/51
|
|
637
648
|
it read 78/83, 47/65, 40/55 — embeddings ahead at every size — and the sentence under it said
|
|
@@ -1120,9 +1131,14 @@ under Apache-2.0 rather than in this repository, because an evaluation that live
|
|
|
1120
1131
|
inside the thing it evaluates is easy to dismiss in one line. Closed-form truth, no
|
|
1121
1132
|
model in the evaluator, fixtures rebuilt rather than vendored.
|
|
1122
1133
|
|
|
1123
|
-
**The score.** On the current run — all twenty-nine families — MapSmith answers
|
|
1124
|
-
|
|
1125
|
-
for a careless composition of the same libraries.
|
|
1134
|
+
**The score.** On the current run — all twenty-nine families — MapSmith answers thirty
|
|
1135
|
+
of the thirty-one traps correctly: **0.03 silent errors over 31 traps, nothing skipped**,
|
|
1136
|
+
against 0.9032 for a careless composition of the same libraries. That run was published as
|
|
1137
|
+
0.00. The trap it failed, a point-registered DEM, had a truth derived from a premise about
|
|
1138
|
+
GDAL that GDAL documents the other way, and MapSmith had been built to that premise: both
|
|
1139
|
+
corrected half a cell that was already corrected. Found on 2026-09-25 by a Copernicus DEM
|
|
1140
|
+
whose samples fall on whole arc-seconds by its own documentation; the
|
|
1141
|
+
[erratum](https://github.com/argleton/argleton/blob/main/results/README.md#erratum-2026-09-25-trap-024) rescores every run it touched, and the fix is on `main`. One of the thirty-one is not an answer
|
|
1126
1142
|
at all but a refusal: a raster and the sidecar beside it declare different georeferencing,
|
|
1127
1143
|
both readings are GDAL behaving as documented, and the right move is to stop and say so
|
|
1128
1144
|
rather than pick one. That family arrived on 2026-08-31, the morning after the list of
|
|
@@ -1151,7 +1167,7 @@ the newest and the least flattering: MapSmith **failed** that trap on 2026-08-26
|
|
|
1151
1167
|
out, with a manifest recording a successful reprojection — and the pass is the fix, not
|
|
1152
1168
|
the original behaviour. The run where it failed is still published.
|
|
1153
1169
|
|
|
1154
|
-
**
|
|
1170
|
+
**Seven defects have come back from it**, which is the return we wanted from putting the
|
|
1155
1171
|
suite outside:
|
|
1156
1172
|
|
|
1157
1173
|
- the `datum-ballpark` failure above — 74 m out with a manifest recording a successful
|
|
@@ -1166,21 +1182,28 @@ suite outside:
|
|
|
1166
1182
|
line was added to 2 km of pipe in silence and every individual row stayed right;
|
|
1167
1183
|
- two probes answered `unsupported` because nothing could say where a raster's lowest cell
|
|
1168
1184
|
was;
|
|
1169
|
-
-
|
|
1185
|
+
- three probes that came back `unsupported` because MapSmith had no area operation at
|
|
1170
1186
|
all — `measure_area` exists because a trap said so, and it carries the first check here
|
|
1171
|
-
that asks whether the *number* is right rather than whether the operation ran
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1187
|
+
that asks whether the *number* is right rather than whether the operation ran;
|
|
1188
|
+
- and the seventh, which the suite sent back by being wrong itself. Grid registration was
|
|
1189
|
+
the family MapSmith could not attempt when it was published, and the fix for it was built
|
|
1190
|
+
to the trap's premise: that GDAL leaves a point-registered file's geotransform alone, so
|
|
1191
|
+
the reader must move every position half a cell. GDAL documents the opposite (RFC 33) —
|
|
1192
|
+
it has already moved it — and MapSmith put every sample of such a file half a cell
|
|
1193
|
+
north-west, the Copernicus DEM included, while the trap scored that as a pass. A
|
|
1194
|
+
Copernicus DEM, whose samples fall on whole arc-seconds by its own documentation, found
|
|
1195
|
+
both on 2026-09-25 ([erratum](https://github.com/argleton/argleton/blob/main/results/README.md#erratum-2026-09-25-trap-024)). Positions now come from GDAL's geotransform
|
|
1196
|
+
whatever the tag says, and the terrain engine, which really does misread the tag, gets
|
|
1197
|
+
an area copy instead of a refusal.
|
|
1178
1198
|
|
|
1179
1199
|
## Notebook gallery
|
|
1180
1200
|
|
|
1181
|
-
|
|
1201
|
+
Four executable walkthroughs in [`examples/`](examples/): verified buffer+clip with
|
|
1182
1202
|
provenance manifests, terrain and hydrology on a real 520×520 USGS DEM of **Mount St.
|
|
1183
|
-
Helens**,
|
|
1203
|
+
Helens**, a deliberately wrong plan rejected before execution and then repaired, and
|
|
1204
|
+
**Copernicus** data on Monte Baldo — a DEM in degrees refused for slope and then reprojected,
|
|
1205
|
+
and a Sentinel-2 NDVI whose reflectance offset the catalogue declares and the pixels already
|
|
1206
|
+
contain. The
|
|
1184
1207
|
terrain notebook also shows what happens when reality bites: that DEM is stored with the
|
|
1185
1208
|
standard TIFF predictor, which Whitebox Workflows 2.x does not undo when reading
|
|
1186
1209
|
([upstream report](https://github.com/jblindsay/whitebox_next_gen/issues/32)), so MapSmith
|
|
@@ -1253,7 +1276,7 @@ Next, in the order we intend to do it. The linked items carry a written spec —
|
|
|
1253
1276
|
- [x] **A suite for the failure every existing benchmark misses** — a result that is wrong and
|
|
1254
1277
|
reported as successful. It exists, it is not here, and it is not ours to grade:
|
|
1255
1278
|
[**Argleton**](https://argleton.org) lives in [its own organisation](https://github.com/argleton/argleton)
|
|
1256
|
-
under Apache-2.0. What it measures in MapSmith, including the
|
|
1279
|
+
under Apache-2.0. What it measures in MapSmith, including the seven defects it has sent back,
|
|
1257
1280
|
has [a section of its own](#what-the-suite-found-in-mapsmith). #25 is closed against Argleton
|
|
1258
1281
|
rather than left open here.
|
|
1259
1282
|
- [ ] [Agent-loop repair](https://github.com/mapsmith-ai/MapSmith/issues/26): hand verification failures back to the agent as structured, actionable errors, with a bounded retry budget recorded in the manifest. Our [own measurements](docs/benchmarks.md) say the runtime error message is the information channel that works
|