Introduce backend/city_copy.json: original, researched per-city editorial copy
(a lede, 2-4 body paragraphs, and a records-page intro), keyed by slug next to
the existing Wikipedia cities_flavor.json. Covers 83 of the 90 cities that had
no flavor blurb at all; each entry carries the independent sources it was
written from and reviewed:false pending a human spot-check.
Wire it end to end:
- cities.copy(slug) loader, mirroring cities.flavor() (lazy, tolerant of a
missing file so pages render fine until copy exists).
- A `copy` field on the city and records content payloads. PAYLOAD_VER p2->p3
so cached content rows rebuild with the new field instead of serving the old
shape.
- city.html.j2 renders the editorial lede + body in place of the Wikipedia
blurb, falling back to the flavor blurb (with its "via Wikipedia" credit)
wherever copy isn't written yet. records.html.j2 gains a per-city intro line
it never had before.
Additive and backward-compatible: no API contract bump, and any slug without a
copy entry keeps its existing behavior.
One root workflow set replaces the four repos' copies (deleted -- root-only
is where Forgejo reads them, and dead copies are a trap): per-domain
build-push with explicit image paths (emi/thermograph/backend|frontend; the
old github.repository-derived path collides in a monorepo), path-filtered
per-domain beta/prod/dev deploys, a domain-input reusable build check, a
single always-reporting PR gate (path-filtered required checks deadlock
auto-merge), a new infra-sync pipeline (host checkout + secrets render on
infra/** pushes), and ports of secrets-guard / ops-cron /
observability-validate to monorepo paths.