2 Commits

Author SHA1 Message Date
6aec00ee29 fix(landscape): accept an empty run body; pin the builder's Alpine release
POST /landscape/runs documents an optional body, but DecodeJSON returned
io.EOF on an empty one and the handler turned that into 400 — breaking the
most common call, an all-defaults run. decodeRunRequest now treats io.EOF as
the zero request; a malformed body is still 400.

The Dockerfile's Alpine ABI coupling was enforced only by a comment: a
floating golang:1.26-alpine builder against a pinned alpine:3.24 runtime
would build green and die at startup on a libgdal soname mismatch as soon as
the Go image rolls forward. Both stages are now pinned to 3.24.

Also: the route-mount test walks the router so all six routes are asserted
(GET /slots and GET /results included), and the spec documents the 404 those
two return when migration 00011's seeded groups are absent.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 14:22:26 +05:00
ad3c9fbdcd feat(landscape): HTTP API, worker consumer, wiring, docs
Adds the /landscape routes (slots, slot upload, runs, run detail, results),
mounts them in the router, wires the landscape repository, job publisher,
godal raster IO and Compute into the composition root, and registers the
gis-landscape-runner consumer in the worker.

Also fixes the Dockerfile so the image actually runs: godal's cgo needs g++,
and the runtime base must match the builder's Alpine release or libgdal's
soname does not resolve.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 14:11:57 +05:00