Nobody reads three major versions of release notes, so upgrades ship on hope and a staging smoke test. Feed the notes, deprecation lists and your feature inventory to AI and get back a risk register: what changes, what breaks, what to test — each item traced to the note that says so.
Tier: Foundation · Workflow area: Schema & Change Management · ~25 minutes
The information needed to de-risk an upgrade is public, complete and unread — thousands of lines of release notes, behavior changes and deprecations between your version and the target. This playbook turns that corpus plus an honest inventory of what your estate actually uses into a prioritized risk register with a test-focus list. The trick is the inventory: release notes only matter where they intersect what you run.
Extract your feature inventory — from the databases, not from memory. What you actually use is queryable:
-- Extensions and versions in each database
SELECT extname, extversion FROM pg_extension;
-- Non-default settings that upgrades love to rename or re-default
SELECT name, setting FROM pg_settings
WHERE source NOT IN ('default', 'override');
-- Features visible in the catalog: partitioning, replication,
-- FDWs, custom types, procedural languages
SELECT count(*) FILTER (WHERE relkind = 'p') AS partitioned_tables,
(SELECT count(*) FROM pg_subscription) AS log_rep_subs,
(SELECT count(*) FROM pg_foreign_table) AS foreign_tables,
(SELECT count(*) FROM pg_language WHERE lanname NOT IN
('internal','c','sql')) AS proc_languages
FROM pg_class;
Add the outside-the-catalog facts: client driver versions, connection poolers, backup tooling, monitoring agents, and any SQL constructs your apps are known to lean on (from pg_stat_statements exports).
Feed notes plus inventory, demand traceability.
You are planning a PostgreSQL 14.11 -> 16.4 upgrade. Below:
(a) our feature inventory (extensions, settings, features, drivers),
(b) the release notes for 15.0 and 16.0 (and the incompatibilities
sections of each), (c) our top-30 query digest.
Build an UPGRADE RISK REGISTER. For each item:
- risk_id, WHAT changes (quote or cite the exact release-note line),
- WHERE it intersects our inventory (name the extension/setting/query),
- IMPACT: breaks / behavior-change / performance-change / removal,
- SEVERITY: high / medium / low for US specifically,
- TEST: the specific staging test that would surface it.
Then: DEPRECATIONS to fix before upgrading, and a NON-ISSUES list —
scary-sounding notes that do NOT apply to us, with why.
Do not include generic upgrade advice. Every row must cite a note line
and an inventory line.
The two-sided citation rule ("a note line AND an inventory line") is what keeps the register grounded — it makes hallucinated risks visible, because they cannot cite both sides.
Verify the high-severity rows against the source. For every row marked high, find the cited line in the actual release notes and confirm it says what the register claims. LLMs summarizing release notes occasionally invert a change ("X is now the default" vs "X is no longer the default"). A verified high row looks like:
R-03 | HIGH | public schema no longer world-writable (PG15 notes,
"Remove PUBLIC creation permission on the public schema")
Intersects: legacy ETL role writes temp tables to public (inventory
line 14; confirmed in pg_stat_statements digest)
Test: run ETL nightly job against PG16 staging under the unchanged
role; expect permission failure until GRANT CREATE applied.
VERIFIED against notes ✓
Turn the register into the staging test plan. Each high and medium row's TEST column becomes a staging task with an owner. Run the plan on a production-restored staging copy at the target version; record pass/fail per risk ID. Deprecation fixes (the "fix before upgrading" list) become normal change tickets sequenced ahead of the upgrade.
File the register as the upgrade's decision record. Go/no-go review walks the register: highs all tested, mediums tested or accepted with a name attached, non-issues spot-checked. After the upgrade, annotate what actually bit — the register's accuracy record is your calibration data for trusting the next one.
utf8mb3 remnants), which is where 5.7→8.0-class upgrades actually break.optimizer_features_enable staging comparisons where flagged.Feature inventories and query digests describe your production architecture — treat the paste as sensitive, strip anything customer-identifying from query samples, and prefer your tenant-approved model for full-estate inventories.
Keep last upgrade's register next to this one and start the prompt with its post-upgrade annotations — "here is what the previous register missed" is the cheapest calibration you can give the model, and it measurably sharpens the new register's severity calls.