Report PostgreSQL collation drift in live smoke
GeoIntel CI / docs-smoke (push) Has been cancelled
GeoIntel CI / contract-smoke (push) Has been cancelled

This commit is contained in:
Codex
2026-06-17 06:47:09 +02:00
parent 4f23b0cd9d
commit 35b42878c7
6 changed files with 122 additions and 0 deletions
+8
View File
@@ -7,6 +7,14 @@
# Changelog
## Sprint 36 PostgreSQL collation maintenance visibility (2026-06-17)
- Added database collation version reporting to `scripts/live_migration_smoke.sh`.
- The live smoke now prints `COLLATION_VERSION_MISMATCH` plus the exact `ALTER DATABASE ... REFRESH COLLATION VERSION` acknowledgement command when an old PostGIS volume is reused on a newer runtime.
- Documented the Unraid maintenance procedure and backup/index review guidance.
- Added regression coverage for the collation mismatch reporting path.
- No API contracts, migrations, product features, provider fetching or AI behavior were introduced.
## Sprint 35 Docker runtime secret hygiene (2026-06-17)
- Removed embedded PostGIS database name/user/password defaults from `deploy/unraid/Dockerfile.all-in-one` image metadata.
@@ -22,3 +22,13 @@ def test_live_migration_smoke_checks_required_runtime_schema_objects() -> None:
assert '"public.detections"' in content
assert '"public.segmentations"' in content
assert '"public.ix_segmentations_geometry"' in content
def test_live_migration_smoke_reports_collation_version_mismatch_without_failing() -> None:
script = Path(__file__).resolve().parents[2] / "scripts" / "live_migration_smoke.sh"
content = script.read_text(encoding="utf-8")
assert "pg_database_collation_actual_version(oid)" in content
assert "COLLATION_VERSION_MISMATCH" in content
assert "REFRESH COLLATION VERSION" in content
assert "Database collation version: ok" in content
+16
View File
@@ -91,6 +91,22 @@ curl -I "http://192.168.10.150:${GEOINTEL_FRONTEND_PORT:-1202}/geointel-icon.svg
curl -I "http://192.168.10.150:${GEOINTEL_FRONTEND_PORT:-1202}/geointel-icon.png"
```
The live migration smoke also checks PostgreSQL database collation metadata.
When reusing a PostGIS volume created by an older Debian/glibc runtime, it may
print `COLLATION_VERSION_MISMATCH`. This is a maintenance warning, not an app
startup failure. Review backups first, then acknowledge the new runtime
collation version inside the running container:
```bash
docker exec -it geointel psql -U "${GEOINTEL_POSTGRES_USER:-geointel}" -d "${GEOINTEL_POSTGRES_DB:-geointel}"
ALTER DATABASE "geointel" REFRESH COLLATION VERSION;
```
If you rely on text indexes with locale-specific ordering, plan a maintenance
window and rebuild the affected indexes before acknowledging the version. The
current GeoIntel V1 spatial workflows primarily use UUIDs, JSON metadata and
PostGIS geometry indexes, but the warning should still be tracked explicitly.
## Change the browser port
Edit `.env`:
+27
View File
@@ -1627,3 +1627,30 @@ Limitations:
Next recommended pass:
- Run release readiness, rebuild/deploy Tower and verify browser/GIS/demo smoke again.
## Sprint 36 PostgreSQL collation maintenance visibility (2026-06-17)
Changed:
- Added PostgreSQL database collation version reporting to `scripts/live_migration_smoke.sh`.
- The live smoke now prints `COLLATION_VERSION_MISMATCH` with stored and actual versions when a reused PostGIS volume was created under an older libc/collation runtime.
- The smoke also prints the exact `ALTER DATABASE "... " REFRESH COLLATION VERSION;` acknowledgement command, but does not run it automatically.
- Documented the Unraid maintenance procedure and backup/index review guidance.
- Added regression coverage for the collation reporting path.
Tested:
- `cd backend && python -m pytest tests/test_live_migration_smoke_script.py -q`
- `bash -n scripts/live_migration_smoke.sh`
- `python -m compileall backend/app`
- `cd backend && python -m pytest -W error::DeprecationWarning`
- `cd frontend && npm run typecheck`
- `cd frontend && npm run build`
- `bash scripts/run_readiness_check.sh`
Open:
- Run the updated smoke against Tower to confirm whether the reused volume still reports a collation mismatch.
Limitations:
- The smoke reports and documents the maintenance action. It intentionally does not mutate collation metadata automatically.
Next recommended pass:
- Run release readiness, deploy Tower and decide whether to manually acknowledge the current collation version.
+1
View File
@@ -13,6 +13,7 @@ This file now starts with the current implementation status. Older preparation/b
- [x] Add Unraid Compose template assets with editable ports, storage path and app icon.
- [x] Add single-container Unraid runtime with embedded PostGIS, backend and frontend.
- [x] Remove embedded PostGIS password defaults from all-in-one Docker image metadata.
- [x] Report reused-volume PostgreSQL collation mismatches in live migration smoke.
## Current implementation status
+60
View File
@@ -69,6 +69,26 @@ required_objects = [
with get_engine().connect() as connection:
postgis_version = connection.execute(text("SELECT PostGIS_Version()")).scalar()
print(f"PostGIS version: {postgis_version}")
collation_row = connection.execute(
text(
"SELECT datname, datcollversion, pg_database_collation_actual_version(oid) AS actual_version "
"FROM pg_database WHERE datname = current_database()"
)
).mappings().one()
stored_version = collation_row["datcollversion"]
actual_version = collation_row["actual_version"]
if stored_version != actual_version:
database_name = str(collation_row["datname"]).replace('"', '""')
print(
"COLLATION_VERSION_MISMATCH: "
f"database={collation_row['datname']} stored={stored_version} actual={actual_version}"
)
print(
"After reviewing backups and indexes, acknowledge with: "
f'ALTER DATABASE "{database_name}" REFRESH COLLATION VERSION;'
)
else:
print("Database collation version: ok")
missing = [
object_name
@@ -154,6 +174,26 @@ required_objects = [
with get_engine().connect() as connection:
postgis_version = connection.execute(text("SELECT PostGIS_Version()")).scalar()
print(f"PostGIS version: {postgis_version}")
collation_row = connection.execute(
text(
"SELECT datname, datcollversion, pg_database_collation_actual_version(oid) AS actual_version "
"FROM pg_database WHERE datname = current_database()"
)
).mappings().one()
stored_version = collation_row["datcollversion"]
actual_version = collation_row["actual_version"]
if stored_version != actual_version:
database_name = str(collation_row["datname"]).replace('"', '""')
print(
"COLLATION_VERSION_MISMATCH: "
f"database={collation_row['datname']} stored={stored_version} actual={actual_version}"
)
print(
"After reviewing backups and indexes, acknowledge with: "
f'ALTER DATABASE "{database_name}" REFRESH COLLATION VERSION;'
)
else:
print("Database collation version: ok")
missing = [
object_name
@@ -267,6 +307,26 @@ required_objects = [
with get_engine().connect() as connection:
postgis_version = connection.execute(text("SELECT PostGIS_Version()")).scalar()
print(f"PostGIS version: {postgis_version}")
collation_row = connection.execute(
text(
"SELECT datname, datcollversion, pg_database_collation_actual_version(oid) AS actual_version "
"FROM pg_database WHERE datname = current_database()"
)
).mappings().one()
stored_version = collation_row["datcollversion"]
actual_version = collation_row["actual_version"]
if stored_version != actual_version:
database_name = str(collation_row["datname"]).replace('"', '""')
print(
"COLLATION_VERSION_MISMATCH: "
f"database={collation_row['datname']} stored={stored_version} actual={actual_version}"
)
print(
"After reviewing backups and indexes, acknowledge with: "
f'ALTER DATABASE "{database_name}" REFRESH COLLATION VERSION;'
)
else:
print("Database collation version: ok")
missing = [
object_name