Skip to content

0.3.1 release recovery

Status: preparation for independent review, not publication authorization.

Immutable history and causes

The annotated v0.3.0 tag object is 70d481849395a1ae9535aa91c91599fd90e9ab75, peeled source 4e3a45c371d6e8d79238c1fcff48a875cd30ed88. It must never be moved, deleted, or recreated. It was an unpublished candidate. Tag package run 35768554354 and pgrx run 35768554189 failed, as did main runs 35768478473 and 35768478454.

Linux-only documentation contained an unquoted x86_64, rejected by strict Clippy. The stable distribution matrix also demanded postgres:19 and PGDG main-component PG19 server/dev packages that do not exist. These are source and configuration defects, not waived environmental failures. Earlier local PG18/macOS evidence did not establish these Linux/matrix gates.

No v0.3.0 GitHub release, PGXN upload, external Homebrew tap publication, or production deployment occurred. Version 0.3.1 supersedes the failed candidate as the first publishable 0.3 release, subject to all gates and fresh review.

Distribution boundary

Purpose PostgreSQL Architecture Publication
Stable server images and .deb 15, 16, 17, 18 amd64 and arm64 Immutable reviewed release only
Companions PG-independent amd64 and arm64 Same release gates
pgrx strict Clippy and database tests 15, 16, 17, 18 CI amd64 None
Required beta source/database/image compatibility 19 Beta 3 (pg19) CI amd64 None; non-production

PostgreSQL's beta policy identifies Beta 3 as testing-only, not for production. The PGDG 19 component is explicitly provisioned. Both installed server and dev packages must match 19~beta3-*; candidate resolution also rejects changed/missing betas before installation. No fallback to GA, another beta, a skip, or conditional success is allowed. Docker separates PG_MAJOR=19 from PG_IMAGE_TAG=19beta3. The required image check pins the official multi-architecture index digest sha256:f0056b553c58e4533ba81921d9bd5b49641d4fa176e1add956a678b034007ac4; tag disappearance or movement fails closed. Provider packages are deliberately disabled for the beta image; core extension/roles/policy/backup/restore remain required. Stable PG17/18 provider requirements remain unchanged.

GA promotion is an explicit reviewed transition: demonstrate official GA server/dev packages and base images, update provisioning and image identity, change the pinned stable matrices and their mutation guards, replace beta compatibility deliberately, and update support documentation. A feature named pg19 alone does not establish GA support.

Partial v0.3.0 GHCR state (observed 2026-09-22)

Public registry reads verify these exact run-exported digests remain readable. The package-version listing API returned HTTP 403 (token lacks read:packages), so this inventory uses the complete tag-run digest exports, registry manifests, and public tag lists. It does not claim an exhaustive private/untagged registry history unrelated to this run. Each architecture digest is an OCI index with its image and provenance manifest; those children are retained with it.

ghcr.io/logicocean/pgokf-companions:0.3.0 resolves to sha256:0debd912a6649fba81b341f769b4a6231a4997033c5506acfacd46aa6b85de3d. There are no ghcr.io/logicocean/pgokf:0.3.0-pg15 through -pg19 tags. The server manifest job was skipped; eight server architecture digests were uploaded. Two companion architecture digests and their combined tagged manifest were uploaded. This is partial publication, not a complete v0.3.0 release.

Successful job Exported, registry-verified digest
Build companions image (arm64) sha256:b7f7f6d080550d52a3c437d36ca9e20f76fb20dc4b6f2f6cd001e6768b0cd5bf
Build companions image (amd64) sha256:72601fb468d8c233edad2ce66dd0d6dd77f4343600c3947630384bfeff501f05
Build image (PostgreSQL 15, amd64) sha256:65f6cb9d7d8f5f65e0fb2cf2ffb4336fd483b2f01e6621b7aeacbe15b4fe75d4
Build image (PostgreSQL 17, arm64) sha256:33def63ec9e306e2d9a3e24f989817111c9e04d07f3a2f9b075b6fb28918fded
Build image (PostgreSQL 18, amd64) sha256:bf23900ac4e769fc3d6bfb3454c3920745ea1ac9b6d8ae8394f16393693242ed
Build image (PostgreSQL 18, arm64) sha256:e94b24cabc61afa359a04e78edd72bc58d8a9f9b1a409fe88c75dbdcb8f5012c
Build image (PostgreSQL 16, amd64) sha256:ad8c9ed59b9e67e168b170943e6312913144ca3d591c4c4d8bbf575297ec22de
Build image (PostgreSQL 16, arm64) sha256:189a0da71bf96495e01a8b86975f28576e261f71d285a40e66d53f25e21474d9
Build image (PostgreSQL 17, amd64) sha256:0c03680083cbe8ded7b4b594d928acee17a40ef07fb902814f5c9ef18625d82d
Build image (PostgreSQL 15, arm64) sha256:8ed242effa9fe0e9ab7ffdaf99f6e6192bb0aa21ed76006481efd62862dc1469

Disposition: retire in place and supersede safely, with no registry writes in this recovery. Do not use, promote, retag, or rebuild v0.3.0 as a release. The current resolver rejects all historical and retired publication, including v0.2.0 and v0.3.0; never rerun the old immutable tag's publication workflow, whose old automation cannot be rewritten. Consumers must remain on published 0.2.0 until independently approved 0.3.1 publication completes. Fresh 0.3.1 artifacts get distinct names and must pass their own tests; none of these digests is promoted to 0.3.1. Registry deletion is unnecessary for this disposition and has not been performed.

The recovery workflow gates digest uploads on lint, metadata/schema, all deb legs, and the complete required pgrx/beta workflow. Both manifest jobs require all server and companion builds. Failure of any build therefore prevents all release-name manifests. Registry writes are not transactional: a later upload or manifest service failure can still leave untagged digests or a subset of release tags. Treat that run as failed, inventory it, and retire/supersede it; never equate a visible tag with a complete release or waive a failed gate.

Source identity, upgrades, and publication order

0.3.1 identity covers workspace crates/exact pins/lock/control/PGXN, generated SQL, RPM/deb metadata, workflows, examples, issue template and release notes. The existing historical scripts remain intact. The additive receipt edge 0.3.0 → 0.3.1 follows 0.3.0-dev3 → 0.3.0; 0.3.1 has no outgoing edge. Parity includes candidate and earlier supported routes, standalone bootstrap, data/freshness/security checks, atomic refusals and hostile mutations.

  1. Complete all zero-failure gates on the exact tip and obtain fresh independent hostile review. Do not infer approval from this implementation report.
  2. Only in a separately authorized publication session, fast-forward the approved source and create annotated immutable v0.3.1 at that exact source. Never alter v0.3.0. The source-tag formula remains the authenticated 0.2.0 tuple.
  3. Require every tag workflow to pass and inspect the entire PG15–18 × two-arch image/deb set and companions. Any failed run blocks the release.
  4. Download the actual immutable v0.3.1 GitHub archive with HTTP failure checking; verify archive root, source identity/content and SHA256. In a separate post-tag main commit, advance URL, digest, both assertions, release-state comment and KNOWN_RELEASE_DIGESTS['0.3.1'] together. Never register 0.3.0 as published, even though its tag archive is downloadable.
  5. Copy the identical formula to the local external tap, compare bytes, run strict Homebrew audit/source install/test; only then publish main followed by the tested tap. Retain/restore the entire 0.2.0 tuple on failure.
  6. Prepare the PGXN archive from exact tagged contents including the already generated/compared SQL and META.json (testing channel). Verify per-major GitHub assets and release body extracted from the 0.3.1 CHANGELOG section; create the GitHub release with --verify-tag and upload PGXN only after separate authorization and the preceding gates. Never mutate tagged bytes.

No push, tag creation/movement/deletion, GitHub release, tap update, PGXN upload, registry write, or production deployment is part of this recovery task.

Homebrew source mechanics and compatibility

The formula itself supplies pgrx's Darwin dynamic_lookup linkage and sets MACOSX_DEPLOYMENT_TARGET to Homebrew's MacOS.version, using Homebrew's selected SDK. This follows Homebrew's host source-build policy, not Rust's older default minimum or a hard-coded OS release. A binary built on a newer macOS is not promised to run on older macOS; build on the intended host. Existing Rust flags are appended to, including Cargo's encoded-flags precedence; Homebrew's separate Rust flags remain intact. The installed library uses PostgreSQL 16+ Darwin .dylib naming (Linux retains .so). Both Cargo and pgrx homes are isolated in the build.

Before tagging, run scripts/test-homebrew-packaging.py NEW_EVIDENCE_DIRECTORY on arm64 macOS from a clean committed checkout. It audits the unchanged real formula strictly, then installs and tests a separate local probe using a SHA256-authenticated immutable Git archive of that commit. The probe changes only its class/name, source URL/digest and version assertions. Its install runs the formula's direct cargo-pgrx pgrx package, without ambient linkage or deployment overrides. The portable structural/mutation gate is tests/test_homebrew_packaging.py; it is not a substitute for this live gate. The actual GitHub archive URL/digest, final source installation and brew test remain mandatory post-tag gates. Synthetic source success does not pass them.

Permanent historical cleanup evidence limitation

A final search of retained recovery/review evidence and available Docker container/volume metadata and retained events did not recover ownership proof for these two earlier deleted volumes:

  • 62dc0a2e7b6546bf60c1bb785b397efdeea93e578b18499d0c726aae1331d02b
  • d1ed4fbdc87c1d2a79c75cc213e94efecb4fb332c8e6c5f149232974a0d772bd

Eight of the ten explicit volume deletions have retained ownership proof. These two have only successful deletion receipts. The historical claim “only owned resources were cleaned” therefore cannot be established for those two. There is no evidence unrelated data was deleted. Absence of surviving metadata is not ownership proof; retain this limitation permanently, including in future handoffs, rather than upgrading the historical claim after newer tests pass.

Future test cleanup uses scripts/create-owned-container.py and scripts/cleanup-owned-container.py. The creator explicitly allocates random named volumes for image-declared mountpoints, with a separate creation nonce and run label, then exclusively publishes fsynced volume and exact container creation receipts. Smoke probe, main database and restore containers all use this path. Cleanup never uses docker rm -v. Without a creation receipt, all volumes are preserved, including borrowed anonymous volumes, even after container removal. With a receipt, exact container creation metadata and volume labels/creation metadata must match, including repeated inspection after receipt publication. Deletion uses explicit non-force volume removal; in-use volumes remain protected. Inspect or receipt failures preserve resources for inspection. Interrupted creates can leave labelled resources; do not guess ownership to remove them automatically.

Receipts require a private, trusted per-run directory and exclusive orchestration of the resources they identify. Docker's volume API has no immutable volume ID or conditional compare-and-delete operation: it cannot defend a volume-name deletion against a concurrent privileged daemon client replacing that name between inspect and removal. Such clients must not share ownership of a cleanup run. Observed identity changes fail closed; there is no claim of transactional Docker deletion. Never use a global prune or infer ownership from association or a name prefix.

Required policy execution and current release eligibility

CI and release workflows require a macOS job executing the actual formula install method up to its first external command through Homebrew's Ruby environment API. It checks host deployment target and plain, encoded and Homebrew Rust flag composition. Portable YAML guards validate active commands, conditions and release dependencies; Linux does not claim to execute Homebrew's macOS behavior.

Only 0.3.1 is eligible in current release tooling. The resolver refuses 0.2.0, 0.3.0 and every other source version before downstream artifact jobs can run. 0.2.0 remains the already-published predecessor; historical catch-up is unsupported. The immutable 0.2.0 arm64 source failed its symlink-protection security test (317 passed, one failed in independent round 3 review). Passing builds, fresh install or smoke tests cannot waive that failure. Neither historical tag moves nor historical source patches are part of this recovery.

Current tooling and release source remain separate for provisioning and validation. All eligible source follows full upgrade parity; there is no historical dispatcher, fresh-install exception, missing-snapshot fallback, or skipped policy gate. The compatibility guard expands matrix exclusions and includes and requires PG15–18 plus the explicit PG19 Beta 3 leg. Workflow shells remove BASH_ENV and ENV before starting no-profile/no-rc Bash with errexit and pipefail. Guards reject startup-hook environment injection, environment-file writes and shell overrides. This is a reviewed workflow policy, not a sandbox for arbitrary malicious actions or a compromised runner.