Skip to content

feat(findings): collation_version_mismatch — the collation library changed under the data - #55

Open
lofoneh wants to merge 2 commits into
pgrundev:mainfrom
lofoneh:feat/collation-version-mismatch
Open

lofoneh wants to merge 2 commits into
pgrundev:mainfrom
lofoneh:feat/collation-version-mismatch

Conversation

@lofoneh

@lofoneh lofoneh commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

What and why

New finding: collation_version_mismatch (PG15+).

The libc/ICU version that defines text sort order is recorded in the catalog
(pg_database.datcollversion, pg_collation.collversion). When the library changes
under the data (OS upgrade, new base image, restore onto another host), every btree
over text sorted by it may be silently out of order: lookups miss rows and UNIQUE
stops catching duplicates. Postgres warns at connect time and repairs nothing.

  • New gauge collector + collation.sql reading this database's mismatches. NULL
    versions (C/POSIX) can't drift and are excluded.
  • Critical when the database default drifted (every unqualified text index uses it),
    warn for a named collation. Object db:<name>, scope infra.
  • Remediation is REINDEX then REFRESH COLLATION VERSION; a caveat says why the
    order matters (refreshing first silences the warning and leaves the indexes corrupt).
  • Catalog Meta, summary, docs/findings/collation_version_mismatch.md, regenerated
    docs index, CHANGELOG.
  • New collation section in --json; SchemaVersion → 1.3.0 (additive).

Heads-up: #46 also bumps the schema (to 1.4.0, with its own 1.3.0 file). Whichever
lands second needs a renumber; happy to rebase onto #46 if it goes first.

Verification

PG18 (glibc 2.41), windows/amd64:

  • TestIntegration_collationVersionMismatch forges a stale datcollversion as
    superuser, runs the real collector, checks the row and the finding, then confirms
    REFRESH COLLATION VERSION clears it.
  • Doc-verify guard runs both new verify queries (108 statements, all pass); full
    collect + cmd/pgbot integration suites green.
  • Through the binary: forged 2.31 vs actual 2.41 → critical, exit 2, collation
    section in --json; cleared after refresh. explain-finding reads the page offline.
  • scripts/gate.sh green.

Checklist

  • scripts/gate.sh passes (builds HEAD, not just the working tree)
  • New SQL is read-only; no EXPLAIN ANALYZE; findings stay deterministic (computed in Go)
  • No PII enters a model.Context / --json / the store — collation names and versions only
  • --json change is additive, model.SchemaVersion bumped + schema regenerated
  • A new finding has a docs/findings/<id>.md page + catalog entry

…anged under the data

The version of libc/ICU that defines text sort order is recorded in the catalog
(pg_database.datcollversion, pg_collation.collversion, PG15+). When the library
changes underneath — an OS upgrade, a new base image, a restore onto another
host — every btree over text sorted by it may be silently out of order: lookups
miss rows and UNIQUE stops catching duplicates. Postgres warns at connect time
and repairs nothing; nothing in pgbot read the versions.

A gauge collector reads this database's mismatches (NULL versions — C/POSIX —
cannot drift and are excluded). The finding is critical when the database
default drifted, since every unqualified text index uses it, and warn for a
named collation. The remediation is REINDEX then REFRESH COLLATION VERSION, and
the caveat says why the order matters: refreshing first silences the warning
and leaves the indexes corrupt.

The integration test forges a stale datcollversion as superuser, runs the real
collector, checks the row and the finding, and confirms REFRESH clears it.
New `collation` section in --json; SchemaVersion 1.3.0 (additive).
…on on PG14

The version check shared a query with datcollversion, which doesn't exist
before PG15, so PG14 errored instead of skipping.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant