# Release Gate Checklist Use this page as the pre-release validation runbook for contributors and agents. It is intentionally command-oriented: start with the local checks, run the aggregate release gate, then add the environment-specific gates that are disabled by default. Run commands from the repository root unless a block starts with `cd graph`. Use disposable databases for every heavy script. Use disposable PostgreSQL clusters for crash, upgrade, and memory-inspection scripts. ## Low-Context Agent Rules Use these rules when an automated or low-context agent runs the checklist: - Treat any nonzero command exit as a failed gate unless the release owner explicitly waives it. - Do not continue after a failed required gate. Capture the command, exit code, and last useful log lines, then stop. - Do not retry a failed gate more than once unless the failure is clearly environmental, such as a transient Docker pull, stale pgrx install, or disposable database name collision. - Do not run `RUN_CRASH=1`, `RUN_TX_DELTA_CRASH=1`, `crash_recovery.sh`, or `tx_delta_crash_recovery.sh` unless `PGDATA` points to a disposable PostgreSQL cluster created for release testing. - Do not run `pg_upgrade_validate.sh` unless both old and new data directories are throwaway directories. - Do not run package-manager `install` or `add` commands without the `sfw` wrapper. - Do not mark skipped opt-in gates as passed. Record them as skipped with a reason and owner. For every gate, record: ```text command: working directory: start time: end time: exit code: result: pass | fail | skipped | waived log or artifact path: notes: ``` ## Pre-Run Sanity Check Run this first and save the output with release evidence: ```bash pwd git rev-parse --show-toplevel git rev-parse HEAD git status --short command -v cargo command -v cargo-pgrx command -v psql command -v createdb command -v dropdb command -v pg_config command -v pgbench command -v docker command -v cargo-deny pg_config --version psql --version docker --version cargo --version cargo pgrx --version cargo deny --version ``` If `PG_CONFIG` is set, also verify it points at the intended PostgreSQL major: ```bash "$PG_CONFIG" --version ``` If the release uses a non-default PostgreSQL connection, record these environment variables before running heavy tests: ```text PGHOST= PGPORT= PGUSER= PGDATABASE= PG_VERSION_FEATURE= PG_CONFIG= ``` The normal PostgreSQL 17 release path should use `PG_VERSION_FEATURE=pg17`. ## Release Owner Summary Before tagging a release, collect successful output for: - docs drift, dependency freshness, formatting, clippy, docs, unit tests, pgrx SQL tests, dependency audit, fuzz compile, and projection fuzz seed corpora; - package validation, fresh install smoke, SQL metadata audit, SQLSTATE/ACL boundary, backup/restore, lock regressions, concurrency stress, synthetic release fixture, playground query gate, GQL write lifecycle gates, named graph gate, durable projection gates, tx-delta lifecycle, and pgbench sync stress; - explicit opt-in gates for Docker smoke, crash recovery, tx-delta crash recovery, PostgreSQL-major matrix, peak RSS, mmap PSS, sanitizer runs, and benchmarks when the release owner requires them. Do not mark release verification complete when a gate is skipped, interrupted, or run against the wrong PostgreSQL major. Rerun the gate or record an explicit release-owner waiver with the exact command, reason, and available evidence. ## Environment Prerequisites Required for the normal PostgreSQL 17 release path: - Rust toolchain for the crate and `cargo-pgrx`. - PostgreSQL server, client tools, and headers for the target major. - `pg_config` for the target major on `PATH`, or set `PG_CONFIG`. - `psql`, `pg_dump`, `pg_restore`, `createdb`, `dropdb`, and related client binaries on `PATH`. - `cargo-deny` for the dependency policy gate. - A pgrx test cluster initialized for the target major. - Docker for Docker, package, playground, or matrix gates. - `pgbench` for sync stress gates. - Nix for regenerating and validating `flake.lock` when the dependency freshness gate reports `github:nixpkgs`, `github:rust-overlay`, or other flake input updates. On macOS, current upstream Nix no longer supports single-user installs; use the official daemon installer on a release machine where system-level `/nix`, user, and launchd changes are acceptable. PostgreSQL 17 is the default release feature: ```bash export PG_VERSION_FEATURE=pg17 export PG_CONFIG=/path/to/postgresql-17/bin/pg_config ``` Initialize pgrx once per machine and PostgreSQL major: ```bash cd graph cargo pgrx init --pg17 "$PG_CONFIG" ``` If pgrx reports SQL definition drift after code changes, reinstall against the same PostgreSQL version: ```bash cd graph cargo pgrx install --pg-config "$PG_CONFIG" --features pg17 --no-default-features ``` ## Fast Preflight Run this before long release gates so basic failures are found quickly: ```bash ./scripts/check_docs_drift.sh python3 scripts/check_dependency_updates.py cd graph cargo fmt --check cargo clippy --features "pg17 development" --all-targets -- -D warnings cargo doc --features pg17 --no-deps cargo test --features pg17 cargo pgrx test --features "pg17 development" pg17 cargo deny check advisories bans licenses sources ``` Documentation doctests are part of the public Rust API contract: ```bash cd graph cargo test --doc --features pg17 ``` ## Documentation And Metadata Checks Run the aggregate docs drift gate from the repository root: ```bash ./scripts/check_docs_drift.sh ``` It runs: ```bash ./scripts/check_doc_references.py ./scripts/check_sql_api_drift.py ./scripts/check_rust_doc_map_drift.py ``` Use targeted inventories when a failure needs diagnosis: ```bash python3 scripts/check_sql_api_drift.py --list-implemented python3 scripts/check_rust_doc_map_drift.py --list ``` Run dependency freshness before release metadata freezes: ```bash python3 scripts/check_dependency_updates.py ``` The dependency checker reports update candidates without rewriting manifests unless an explicit `--update ... --yes` is passed. Any package-manager command that installs or adds a new dependency must use `sfw`. ## Rust And SQL Test Layers Use the narrowest layer while iterating, then run the broader release layers. | Layer | Command | Required before release | |---|---|---| | Formatting | `cd graph && cargo fmt --check` | Yes | | Clippy | `cd graph && cargo clippy --features "pg17 development" --all-targets -- -D warnings` | Yes | | Rust unit tests | `cd graph && cargo test --features pg17` | Yes | | Rust docs | `cd graph && cargo doc --features pg17 --no-deps` | Yes | | Rust doctests | `cd graph && cargo test --doc --features pg17` | Yes | | pgrx SQL tests | `cd graph && cargo pgrx test --features "pg17 development" pg17` | Yes | | Dependency audit | `cd graph && cargo deny check advisories bans licenses sources` | Yes | | pgrx focused test | `cd graph && cargo pgrx test pg17 ` | Iteration only | | pg_regress setup smoke | `graph/tests/pg_regress/` | Packaging-style smoke only | The pgrx SQL test files live in `graph/src/pg_tests/` and cover discovery, GQL, Cypher compatibility, traversal, paths, filters, registration/search, sync/config/build behavior, maintenance/admin APIs, named graphs, workflow APIs, validation, and synthetic release SQL shape. ## Fuzz Gates The release gate compiles fuzz binaries with `cargo check --bins` inside `graph/fuzz` and runs projection seed corpora: ```bash cd graph (cd fuzz && cargo check --bins) ./fuzz/run_projection_seed_corpora.sh ``` When a release includes parser, loader, filter, sync, traversal option, or projection format changes, also run the cargo-fuzz compile smoke: ```bash cd graph/fuzz cargo fuzz build ``` Fuzz targets currently cover: | Target | Boundary | |---|---| | `load_graph_file` | Persisted graph artifact loader | | `node_ref_string` | Node reference parser | | `traverse_options` | Traversal option parser | | `sync_properties` | Sync JSON property parser | | `structured_filter` | Structured filter validation | | `gql_parser` | GQL parser frontend | | `cypher_parser` | openCypher compatibility parser frontend | | `load_projection_manifest` | Durable projection manifest loader | | `load_projection_segment` | Durable projection segment loader | ## Aggregate Release Gate Run the main PostgreSQL 17 release gate from `graph/`: ```bash cd graph PG_VERSION_FEATURE=pg17 ./tests/heavy/run_release_gate.sh ``` By default, this gate runs: - `cargo fmt --check`; - `cargo clippy --features "pg17 development" --all-targets -- -D warnings`; - `cargo doc --features pg17 --no-deps`; - `cargo test --features pg17`; - `cargo pgrx test --features "pg17 development" pg17`; - `cargo deny check advisories bans licenses sources`; - fuzz binary compile and projection fuzz seed corpora; - `package_validate.sh`; - `fresh_install_smoke.sh`; - `function_metadata_audit.sh`; - `run_sqlstate_acl_boundary.sh`; - `backup_restore_validate.sh`; - `background_job_lock_regression.sh`; - `build_lock_regression.sh`; - `concurrency_stress.sh`; - `synthetic_release_smoke.sh`; - `playground_release_gate.sh`; - `run_pgbench_sync.sh`; - `gql_create_tx_lifecycle.sh`; - `gql_set_tx_lifecycle.sh`; - `gql_delete_tx_lifecycle.sh`; - `gql_merge_race.sh`; - `named_graphs_heavy_gate.sh`; - `cross_backend_durable_projection.sh`; - `projection_recovery_gate.sh`; - `tx_delta_lifecycle.sh`; - `gql_write_recheck_race.sh`. The default gate does not run Docker smoke, crash recovery, tx-delta crash recovery, full PostgreSQL-major matrix, or peak RSS. Enable those explicitly. ## Full Production Gate Use a disposable PostgreSQL cluster for crash gates. Do not point `PGDATA` at a development database you care about, and never at production. ```bash cd graph PG_VERSION_FEATURE=pg17 \ DB_PREFIX=pggraph_release \ RUN_DOCKER=1 \ RUN_CRASH=1 \ RUN_TX_DELTA_CRASH=1 \ RUN_FULL_MATRIX=1 \ RUN_RSS=1 \ PGDATA=/path/to/disposable/pgdata \ ./tests/heavy/run_release_gate.sh ``` For a staged environment that cannot run Docker, playground, pgbench, or crash checks, make skips explicit in the command and record why: ```bash cd graph PG_VERSION_FEATURE=pg17 \ DB_PREFIX=pggraph_release_staged \ RUN_PLAYGROUND=0 \ RUN_PGBENCH=0 \ RUN_DOCKER=0 \ RUN_CRASH=0 \ RUN_TX_DELTA_CRASH=0 \ ./tests/heavy/run_release_gate.sh ``` ## Release Gate Toggles `run_release_gate.sh` accepts these environment variables: | Variable | Default | Meaning | |---|---:|---| | `PG_VERSION_FEATURE` | `pg17` | Cargo/PostgreSQL feature to test | | `DB_PREFIX` | `pggraph_release` | Prefix for disposable database names | | `RUN_FULL_MATRIX` | `0` | Run local PostgreSQL-major matrix first | | `RUN_PACKAGE` | `1` | Run package validation | | `RUN_INSTALL` | `1` | Run fresh install smoke | | `RUN_METADATA` | `1` | Run SQL function metadata audit | | `RUN_BOUNDARY` | `1` | Run SQLSTATE/ACL boundary tests | | `RUN_BACKUP_RESTORE` | `1` | Run backup/restore validation | | `RUN_BACKGROUND_LOCK` | `1` | Run background-job lock regression | | `RUN_BUILD_LOCK` | `1` | Run build/vacuum lock regression | | `RUN_CONCURRENCY` | `1` | Run mixed concurrency stress | | `RUN_SYNTHETIC` | `1` | Run synthetic release fixture | | `RUN_PLAYGROUND` | `1` | Run playground query gate | | `RUN_PGBENCH` | `1` | Run pgbench sync stress | | `RUN_GQL_CREATE_TX` | `1` | Run GQL `CREATE` transaction lifecycle | | `RUN_GQL_SET_TX` | `1` | Run GQL `SET` transaction lifecycle | | `RUN_GQL_DELETE_TX` | `1` | Run GQL `DELETE` transaction lifecycle | | `RUN_GQL_MERGE_RACE` | `1` | Run GQL `MERGE` race proof | | `RUN_GQL_WRITE_RECHECK` | `1` | Run GQL stale-predicate recheck race proof | | `RUN_TX_DELTA_LIFECYCLE` | `1` | Run internal tx-delta lifecycle proof | | `RUN_NAMED_GRAPHS_HEAVY` | `1` | Run named graph heavy policy gate | | `RUN_CROSS_BACKEND_DURABLE` | `1` | Run cross-backend durable projection gate | | `RUN_PROJECTION_RECOVERY` | `1` | Run projection recovery gate | | `RUN_DOCKER` | `0` | Run Docker smoke | | `RUN_CRASH` | `0` | Run crash recovery, requires disposable `PGDATA` | | `RUN_TX_DELTA_CRASH` | `0` | Run tx-delta crash recovery, requires disposable `PGDATA` | | `RUN_RSS` | `0` | Run peak RSS measurement | Synthetic fixture tuning: | Variable | Default | |---|---:| | `SYNTHETIC_NODE_COUNT` | `50000` | | `SYNTHETIC_HUB_FANOUT` | `1000` | | `SYNTHETIC_MAX_BUILD_MS` | `60000` | | `SYNTHETIC_MAX_QUERY_MS` | `1000` | pgbench sync tuning: | Variable | Default | |---|---:| | `CLIENTS` | `4` | | `JOBS` | `2` | | `TIME` | `30` | ## Heavy Script Inventory Run these from `graph/`. Most accept `PG_VERSION_FEATURE=pg17` and a disposable `DBNAME`. Scripts that kill, upgrade, or inspect PostgreSQL clusters require disposable cluster paths. | Script | Release purpose | Example | |---|---|---| | `run_release_gate.sh` | Aggregate release gate | `PG_VERSION_FEATURE=pg17 ./tests/heavy/run_release_gate.sh` | | `run_pg_matrix.sh` | Local PostgreSQL 14 through 18 matrix | `./tests/heavy/run_pg_matrix.sh` | | `run_pg_matrix_docker.sh` | Docker PostgreSQL-major matrix | `./tests/heavy/run_pg_matrix_docker.sh` | | `package_validate.sh` | Validate pgrx package shape and companion files | `PG_VERSION_FEATURE=pg17 ./tests/heavy/package_validate.sh` | | `fresh_install_smoke.sh` | Install extension and run quick workflow | `PG_VERSION_FEATURE=pg17 DBNAME=pggraph_install ./tests/heavy/fresh_install_smoke.sh` | | `function_metadata_audit.sh` | Audit SQL volatility, security, cost, rows, and parallel metadata | `PG_VERSION_FEATURE=pg17 DBNAME=pggraph_metadata ./tests/heavy/function_metadata_audit.sh` | | `run_sqlstate_acl_boundary.sh` | Assert client-visible SQLSTATEs and restricted-role ACL behavior | `PG_VERSION_FEATURE=pg17 DBNAME=pggraph_boundary ./tests/heavy/run_sqlstate_acl_boundary.sh` | | `backup_restore_validate.sh` | Validate dump/restore of source tables, graph catalog, sync state, and persisted graph behavior | `PG_VERSION_FEATURE=pg17 SOURCE_DB=pggraph_backup_src RESTORE_DB=pggraph_backup_dst ./tests/heavy/backup_restore_validate.sh` | | `background_job_lock_regression.sh` | Check background job lock and failure-state behavior | `PG_VERSION_FEATURE=pg17 DBNAME=pggraph_background_lock ./tests/heavy/background_job_lock_regression.sh` | | `build_lock_regression.sh` | Check build/vacuum lock conflict behavior | `PG_VERSION_FEATURE=pg17 DBNAME=pggraph_build_lock ./tests/heavy/build_lock_regression.sh` | | `concurrency_stress.sh` | Exercise build, sync, vacuum, maintenance, and traversal concurrently | `PG_VERSION_FEATURE=pg17 DBNAME=pggraph_concurrency CLIENTS=3 ROUNDS=3 ./tests/heavy/concurrency_stress.sh` | | `synthetic_release_smoke.sh` | Deterministic release fixture for build, persistence, traversal, search, filters, paths, and components | `DBNAME=pggraph_synthetic NODE_COUNT=50000 HUB_FANOUT=1000 ./tests/heavy/synthetic_release_smoke.sh` | | `run_synthetic_release_evidence.sh` | Synthetic smoke plus metadata and persisted artifact inspection | `NODE_COUNT=50000 HUB_FANOUT=1000 ./tests/heavy/run_synthetic_release_evidence.sh` | | `playground_release_gate.sh` | Validate every playground sidebar query against stable summaries | `PGGRAPH_PLAYGROUND_YES=1 ./tests/heavy/playground_release_gate.sh` | | `run_pgbench_sync.sh` | Concurrent DML and trigger-sync stress | `DBNAME=pggraph_pgbench CLIENTS=4 JOBS=2 TIME=30 ./tests/heavy/run_pgbench_sync.sh` | | `read_latency_under_sync.sh` | Measure read p50/p95/p99 with no backlog, pending backlog, and concurrent writers | `DBNAME=pggraph_read_latency NODE_COUNT=10000 SAMPLES=25 ./tests/heavy/read_latency_under_sync.sh` | | `gql_create_tx_lifecycle.sh` | Public mapped GQL `CREATE` commit and rollback proof | `PG_VERSION_FEATURE=pg17 DBNAME=pggraph_gql_create_tx ./tests/heavy/gql_create_tx_lifecycle.sh` | | `gql_set_tx_lifecycle.sh` | Public mapped GQL property `SET` rollback and filter-delta proof | `PG_VERSION_FEATURE=pg17 DBNAME=pggraph_gql_set_tx ./tests/heavy/gql_set_tx_lifecycle.sh` | | `gql_delete_tx_lifecycle.sh` | Public mapped GQL edge-row `DELETE` rollback and tombstone proof | `PG_VERSION_FEATURE=pg17 DBNAME=pggraph_gql_delete_tx ./tests/heavy/gql_delete_tx_lifecycle.sh` | | `gql_merge_race.sh` | Concurrent mapped `MERGE` same-key convergence proof | `PG_VERSION_FEATURE=pg17 DBNAME=pggraph_gql_merge_race ./tests/heavy/gql_merge_race.sh` | | `gql_write_recheck_race.sh` | Two-session stale predicate recheck proof for mapped writes | `PG_VERSION_FEATURE=pg17 DBNAME=pggraph_gql_write_recheck ./tests/heavy/gql_write_recheck_race.sh` | | `tx_delta_lifecycle.sh` | Internal mutable-overlay transaction lifecycle proof | `PG_VERSION_FEATURE=pg17 DBNAME=pggraph_tx_delta ./tests/heavy/tx_delta_lifecycle.sh` | | `named_graphs_heavy_gate.sh` | Named-graph behavior and policy guardrails | `PG_VERSION_FEATURE=pg17 DBNAME=pggraph_named_graphs bash ./tests/heavy/named_graphs_heavy_gate.sh` | | `cross_backend_durable_projection.sh` | Cross-backend visibility for durable mutable projection state | `PG_VERSION_FEATURE=pg17 DBNAME=pggraph_cross_backend bash ./tests/heavy/cross_backend_durable_projection.sh` | | `projection_recovery_gate.sh` | Durable projection recovery behavior | `PG_VERSION_FEATURE=pg17 DBNAME=pggraph_projection_rec bash ./tests/heavy/projection_recovery_gate.sh` | | `docker_smoke.sh` | Build root Docker image and run extension workflow in container | `IMAGE=pggraph:smoke CONTAINER=pggraph-smoke PG_MAJOR=17 ./tests/heavy/docker_smoke.sh` | | `crash_recovery.sh` | Kill and restart disposable postmaster, then verify reload and corrupt artifact rejection | `PG_VERSION_FEATURE=pg17 DBNAME=pggraph_crash PGDATA=/path/to/disposable/pgdata ./tests/heavy/crash_recovery.sh` | | `tx_delta_crash_recovery.sh` | Kill disposable postmaster with uncommitted overlay and verify it does not persist | `PG_VERSION_FEATURE=pg17 DBNAME=pggraph_tx_delta_crash PGDATA=/path/to/disposable/pgdata ./tests/heavy/tx_delta_crash_recovery.sh` | | `pg_upgrade_validate.sh` | Run `pg_upgrade --check` for a database containing pgGraph | `OLD_BINDIR=/path/to/old/bin NEW_BINDIR=/path/to/new/bin OLD_DATADIR=/tmp/pg-old NEW_DATADIR=/tmp/pg-new ./tests/heavy/pg_upgrade_validate.sh` | | `measure_build_rss.sh` | Capture peak backend RSS during graph build | `PG_VERSION_FEATURE=pg17 DBNAME=pggraph_rss NODE_COUNT=200000 MAX_RSS_MB=0 ./tests/heavy/measure_build_rss.sh` | | `measure_mmap_pss.sh` | Linux-only mmap sharing PSS measurement across backends | `DBNAME=graph_test BACKENDS=50 ./tests/heavy/measure_mmap_pss.sh` | | `run_memory_sanitizers.sh` | pgrx suite plus optional ASan or Valgrind checks | `DBNAME=pggraph_pgbench ./tests/heavy/run_memory_sanitizers.sh` | `pgbench_sync.sql`, `sqlstate_acl_boundary.sql`, and `playground_release_gate.py` are support files used by the shell gates. ## Crash, Upgrade, And Cluster Safety Crash gates deliberately kill PostgreSQL. Run them only against a disposable cluster, and pass restart options when the instance uses custom socket or port settings: ```bash cd graph PGHOST=/tmp/pggraph-crash \ PGPORT=55437 \ PGDATA=/tmp/pggraph-crash/data \ POSTGRES_CTL=/path/to/pg_ctl \ POSTGRES_OPTS="-p 55437 -k /tmp/pggraph-crash" \ DBNAME=pggraph_release_crash \ ./tests/heavy/crash_recovery.sh ``` Run the tx-delta crash gate with the same disposable cluster pattern: ```bash cd graph PGHOST=/tmp/pggraph-crash \ PGPORT=55437 \ PGDATA=/tmp/pggraph-crash/data \ POSTGRES_CTL=/path/to/pg_ctl \ POSTGRES_OPTS="-p 55437 -k /tmp/pggraph-crash" \ PG_CONFIG=/path/to/pg_config \ PG_VERSION_FEATURE=pg17 \ DBNAME=pggraph_release_tx_delta_crash \ ./tests/heavy/tx_delta_crash_recovery.sh ``` Run upgrade validation only with throwaway old and new data directories: ```bash cd graph OLD_BINDIR=/path/to/old/bin \ NEW_BINDIR=/path/to/new/bin \ OLD_DATADIR=/tmp/pggraph-old \ NEW_DATADIR=/tmp/pggraph-new \ ./tests/heavy/pg_upgrade_validate.sh ``` ## Matrix Gates Run the local PostgreSQL-major matrix when all supported `pg_config` binaries are available: ```bash cd graph ./tests/heavy/run_pg_matrix.sh ``` Use Docker when local headers are unavailable: ```bash cd graph ./tests/heavy/run_pg_matrix_docker.sh ``` The project supports PostgreSQL 14 through 18 in release automation. If a matrix leg is skipped locally, record which major was skipped and where it will be validated. ## Performance And Benchmark Evidence Run Criterion when engine-level traversal, filter, storage, or overlay changes could affect hot paths: ```bash cd graph cargo bench --bench bfs_bench ``` When comparing against a saved Criterion baseline: ```bash cd graph cargo bench --features pg17 --bench bfs_bench -- --baseline pre_release ``` Run SQL-facing benchmark harnesses only when the release owner asks for performance evidence or the change affects SQL-facing query timing: ```bash sandbox/run_benchmarks.sh panama sandbox/run_benchmarks.sh ldbc sandbox/run_benchmarks.sh all --yes ``` Keep generated `report.json` files with release evidence. Include the exact command, commit, dirty status, PostgreSQL version, Docker resource settings, machine details, and whether the host was otherwise idle. Run read-latency evidence when query-time sync semantics or topology-read freshness change: ```bash cd graph DBNAME=pggraph_read_latency \ NODE_COUNT=10000 \ SAMPLES=25 \ CONCURRENT_SAMPLES=25 \ SMALL_BACKLOG=100 \ LARGE_BACKLOG=5000 \ CLIENTS=4 \ JOBS=2 \ TIME=30 \ RATE=100 \ ./tests/heavy/read_latency_under_sync.sh ``` Keep `read-latency-samples.csv` and `read-latency-summary.csv` with milestone evidence. ## Package And Publish Workflow Checks Publishing requires four explicit release-owner steps after all required gates pass: tag, sign, package, and push. Do not start these steps from a dirty worktree or from a commit that has not completed the required release gate. Required local state: - The release commit is checked out and `git status --short` is empty. - `graph/Cargo.toml`, package metadata, docs, Docker defaults, and release notes identify the intended version. - `scripts/validate_release.py --tag vX.Y.Z --check-main` passes. - A signing key is configured for Git tags. Use the repository's required signing backend, such as GPG, SSH signing, or the platform-managed signing flow. - Docker is available if preparing Docker images or validating playground packaging. - PGXN credentials, GitHub credentials, Docker registry credentials, and any required 2FA/session state are available to the release owner. Before release automation: ```bash ./scripts/clean_generated_artifacts.sh --dry-run ./scripts/check_docs_drift.sh python3 scripts/check_dependency_updates.py cd graph PG_VERSION_FEATURE=pg17 ./tests/heavy/package_validate.sh PG_VERSION_FEATURE=pg17 DBNAME=pggraph_install ./tests/heavy/fresh_install_smoke.sh ``` Create the signed release tag only after the release commit and evidence are final: ```bash git status --short git log -1 --oneline git tag -s vX.Y.Z -m "vX.Y.Z" git tag -v vX.Y.Z ``` If the project uses SSH tag signing instead of GPG, configure Git before creating the tag: ```bash git config gpg.format ssh git config user.signingkey /path/to/release-signing-key.pub git tag -s vX.Y.Z -m "vX.Y.Z" git tag -v vX.Y.Z ``` Build and validate release packages before pushing the tag: ```bash scripts/validate_release.py --tag vX.Y.Z --check-main cd graph PG_VERSION_FEATURE=pg17 ./tests/heavy/package_validate.sh ``` Push only after package validation and tag verification pass: ```bash git push origin HEAD git push origin vX.Y.Z ``` The GitHub Actions release workflow has two manual phases: | Phase | Required state | |---|---| | `prepare` | Tag exists, release metadata validates, prepared Docker images and PGXN archive build and verify | | `publish` | GitHub Release exists, prepared artifacts match the release tag, Docker manifests and PGXN archive publish without rebuild | Run the `prepare` phase first and inspect its generated artifacts before publishing. The `publish` phase must consume prepared artifacts for the exact tag; it must not rebuild from a moving branch or untagged commit. Use this when validating release metadata locally: ```bash scripts/validate_release.py --tag vX.Y.Z --check-main ``` ## Evidence Template Record this for each release candidate: ```text Release candidate: Commit: Dirty status: Date: Machine/OS: PostgreSQL major: PG_CONFIG: pgrx version: Docker version: Required gates: - docs drift: - dependency freshness: - fmt: - clippy: - cargo doc: - cargo test: - cargo test --doc: - cargo pgrx test: - cargo deny: - fuzz compile: - projection seed corpora: - aggregate release gate: Opt-in gates: - Docker smoke: - crash recovery: - tx-delta crash recovery: - PostgreSQL-major matrix: - RSS/PSS: - sanitizer: - Criterion: - sandbox benchmark: Skipped gates and waivers: - gate: reason: owner: follow-up: ``` ## Related References - [Testing And Release](./testing-release) - [SQL Tests](./sql-tests) - [Scripts](./scripts) - [Benchmarking](./benchmarking)