document selection-bounded change detection and export provenance

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Jens
2026-08-22 14:56:38 +02:00
co-authored by Claude Opus 5
parent 9614307669
commit 52c2bfd120
2 changed files with 53 additions and 2 deletions
+44 -2
View File
@@ -1080,6 +1080,21 @@ Return vector stats (feature counts and geometry summary).
Return vector bounds and feature count.
### Export provenance
Every exported GeoJSON carries a `geointel_provenance` foreign member on the
FeatureCollection. RFC 7946 requires parsers to ignore members they do not
know, so QGIS and ogr2ogr read the file normally.
It names the source, the dataset and its `source_version`/`observed_at`, the
selection the export was taken from, and — most importantly — whether the file
is complete. A capped selection export previously recorded `truncated` on the
export *record* only: the downloaded file looked whole, and an operator opening
250 of 1.400 buildings in QGIS had nothing to tell them so. Completeness is
derived from the counts as well as the flag, so a caller that forgets to pass
it cannot produce a file that claims to hold everything.
### POST `/api/v1/projects/{project_id}/datasets/{dataset_id}/vector/select`
Selection metrics describe two different populations and now say so.
@@ -2015,7 +2030,7 @@ If the segmentation run has no persisted geometries, the endpoint returns `SEGME
### POST `/api/v1/analysis/change-detection`
Compares two persisted vector datasets in the same project and returns a synchronous
job envelope. This is a lightweight V1 foundation for added/removed object review,
job envelope. This is a lightweight V1 foundation for object-level change review,
not a temporal run-history engine.
Request:
@@ -2025,10 +2040,37 @@ Request:
"source_dataset_id": "uuid",
"target_dataset_id": "uuid",
"iou_threshold": 0.8,
"include_unchanged": true
"modified_threshold": 0.3,
"include_unchanged": true,
"bbox": {"min_x": 5.0, "min_y": 51.1, "max_x": 5.2, "max_y": 51.3, "crs": "EPSG:4326"},
"area_id": "uuid",
"preview_limit": 2000
}
```
`bbox` and `area_id` bound the comparison to the operator's selection, resolved
the same way every other analysis resolves it: the drawn rectangle intersected
with the named work area. Both populations are loaded through an indexed
`ST_Intersects` predicate rather than being read into Python in full. Without a
selection the comparison still covers both datasets entire, which is rarely the
question and — with `include_unchanged` true — previously returned a
FeatureCollection holding both datasets.
Features are **not** clipped to the selection. A change class describes a whole
object, so comparing a clipped earlier footprint against an unclipped later one
would manufacture "modified" along the selection edge. Features the edge crosses
are compared in full and counted in a warning instead.
`modified_threshold` separates a redrawn footprint from two distinct objects.
Between it and `iou_threshold` the change class is `modified`; below it the
source is `removed` and the target `added`. Without that class an extended
building appeared as one removal plus one addition, hiding the category the
analysis exists to show and inflating both counts.
`preview_limit` caps the returned geometry — modified, added, removed and only
then unchanged — while every count still describes the whole selection.
`preview_truncated` says whether the cap applied.
Response is a canonical API envelope containing a `JobRead` payload. On success,
`result_json` contains: