ci: define and enforce prerelease payload identity - #179
Conversation
b8ff802 to
22fe149
Compare
Blocking pre-merge review —
|
22fe149 to
0a47899
Compare
|
Addressed both blocking findings from the pre-merge review in
Validation after rebasing onto current The PR body contains the verbatim RED/GREEN evidence for both findings and the corrected overlay guarantee. The PR remains draft. |
0a47899 to
a9b21b4
Compare
The prior helper appended any lone development installer after validating only the migration files. A 2.1 installer over a graph ending at 2.0 therefore emitted SQL and could hide a missing 2.0-to-2.1 migration. Preflight the overlay before any include is emitted. Migration-free overlays must stay on the validated release line and are allowed only while the shipped payload is a prerelease; a final payload requires a connected development migration. RED: the next-line fixture failed with "SystemExit not raised". GREEN: all 16 release-stamp/chain tests pass, including same-line beta-to-final, connected-migration ownership, next-line rejection, and final-release rejection.
After promotion removes devel/sql/ash-install.sql, the overlay-only guard no longer runs. A shipped 2.1 installer could therefore sit over a released graph ending at 2.0; historical shims replay the current installer, allowing upgrade and schema-equivalence gates to mask the missing edge. Validate the shipped installer release line against the released graph head before tracing or emitting any upgrade chain. Development migrations may still extend beyond that released head, while promoted payloads require the corresponding migration to be promoted too. RED: the promoted-next-line fixture failed with "SystemExit not raised". GREEN: all 17 release-stamp/chain tests pass and every rejection asserts zero emitted SQL.
samo-agent
left a comment
There was a problem hiding this comment.
Final pre-merge review — codex review standing in for REV
Verdict: PASS on exact head eba138f9408fd33f38065abaff73eb7024daec0f.
- Hand-rebased onto exact base
bfde011. All four original commits are patch-identical in range-diff; the only overlap was the workflow, which applied text-clean and preserves #192’s 848 inline assertions, PG19beta2, extracted #198/#199 gates, and all feature/degraded surfaces. Size: 509,333 bytes. - Owner identity decision is implemented exactly: final
v2.0↔ payload2.0;v2.0-beta1passes;v2.0.0is rejected. Released SQL is untouched and no tag/release is created. - The prior blocking P1/P2 findings remain fixed: generated pinned v1.5 chains include the candidate overlay, and disconnected graphs fail before emission.
- Final audit found two adjacent preflight gaps and fixed them in
7c34c57/eba138f: migration-free development overlays must be same-line and post-prerelease, and a promoted shipped installer must match the released migration head. - RED is discriminating: the old helper raised no
SystemExitfor next-line, post-final same-line, or promoted-next-line missing-migration fixtures. GREEN is 17/17; every negative fixture also requires empty stdout. Positive controls retain beta→final full/reapply/pinned paths and connected development migrations. - Disposable PG17 upgrade-chain passes, including actual-v1.5 wrapper/reapply, reader grants and least privilege, config ordinal checks, and both schema-equivalence comparisons.
- Exact-head Test is green: https://github.com/NikolayS/pg_ash/actions/runs/30317124198
- Exact-head CodeQL is green: https://github.com/NikolayS/pg_ash/actions/runs/30317122014
- YAML/Python syntax, helper parser tests 7/7, diff check, and frozen released-SQL check pass.
Non-blocking release-stamp reminder: the eventual v2.0 stamp must update human-readable installer/migration comments as well as the three machine-checked stamps.
No merge blocker remains.
Summary
vMAJOR.MINORrelease scheme and the existingvX.Y-alphaN,vX.Y-betaN, andvX.Y-rcNprerelease shapes;videntity against all threeash.config.versionstamp sites;v*tag-push backstop;2.0-beta1→ final2.0upgrade path.Refs #146.
This PR deliberately does not perform the final 2.0 release stamp: it does not change released SQL, promote
devel/sql/, createv2.0, or publish a release. When that release-stamp PR is made, the tag must be exactlyv2.0and every payload stamp must be exactly2.0.Policy
vX.Y-alphaNX.Y-alphaNvX.Y-betaNX.Y-betaNvX.Y-rcNX.Y-rcNvX.YX.YPrerelease tags and their payloads are immutable releases. If SQL changes after a prerelease, the changed payload is staged under
devel/sql/and receives a new identity in the next release-stamp PR. All release identity surfaces must agree; only the Git tag has the leadingv.This preserves the scheme used by the existing tags. The version-schema line in
CLAUDE.mdremains unchanged:vMAJOR.MINOR. The cumulative 2.0 migration remainssql/migrations/ash-1.5-to-2.0.sql; no beta-specific bridge is introduced, and its checked-in copy becomes final and immutable atv2.0.Enforcement and CI
devel/scripts/check_release_stamp.py:vX.Y,vX.Y-alphaN,vX.Y-betaN, orvX.Y-rcN, without leading zeroes or hardcoded release numbers;vwith shippedsql/ash-install.sql, so a development overlay cannot mask the released payload;.github/workflows/test.ymlkeeps both release gates:workflow_dispatch.release_tagruns the identity check before a tag is created;v*tag runs the same check as a backstop.devel/scripts/ash_sql_chain.pynow validates that every released/development migration edge is reachable from a released installer and that each requested start reaches the graph head before emitting any SQL. Itspinned-upgrade-chainemits the public compatibility wrapper first, continues through connected migrations, and appends a lone post-prereleasedevel/sql/ash-install.sqlonly when no connected development migration already owns that overlay. Both pinned v1.5 gates use that composed path, as do the existing full-upgrade and re-apply paths.RED
After changing the tests to the owner-selected two-part contract, the old three-part implementation failed as expected:
GREEN
Blocking review follow-up (TASK2)
The overlay guarantee is now explicit and enforced: before any SQL is emitted, every released/development migration edge must be reachable from a released installer, and the requested start must reach the graph head. The pinned v1.5 behavioral and schema-equivalence gates use a helper-generated chain that executes the public `sql/ash-1.5-to-2.0.sql` wrapper and then the candidate overlay.
Finding 1 — pinned v1.5 gates include the overlay
RED, with a temporary `devel/sql/ash-install.sql` stamped `2.0`:
```text
test_pinned_v15_gate_matches_fresh_candidate ... FAIL
fresh_version=2.0
pinned_v1_5_version=2.0-beta1
AssertionError: fresh path '2.0' != pinned v1.5 path '2.0-beta1'
```
GREEN, using the helper-generated pinned public-wrapper chain:
```text
test_pinned_v15_gate_matches_fresh_candidate ... ok
fresh_version=2.0
pinned_v1_5_version=2.0
Pinned v1.5 path and fresh path converge at '2.0'
```
The exact pinned behavioral gate and the schema-equivalence gate also passed on PostgreSQL 17.9 with that staged candidate, including state/reader-grant preservation and wrapper-chain re-application.
Finding 2 — disconnected graphs fail before emission
RED, for released `1.0→1.1` plus detached `1.2→1.3` and a development installer:
```text
test_disconnected_released_chain_is_rejected ... FAIL
emitted chain:
\i sql/ash-1.0.sql
\i sql/migrations/ash-1.0-to-1.1.sql
\i devel/sql/ash-install.sql
AssertionError: SystemExit not raised
```
GREEN, for the same graph:
```text
test_disconnected_released_chain_is_rejected ... ok
SystemExit: disconnected released upgrade chain from 1.0: stopped at 1.1, expected to reach 1.3
emitted chain:
```
The focused suite now passes 14 tests: the 11 original tests, the two blocking-finding regressions, and an additional detached-edge-below-head hardening case.
Verified
2.0-beta1→2.0upgradeThe rehearsal used the exact tagged beta installer and a temporary final candidate archived from the final rebased PR head. Only the installer header and its three payload stamp literals were changed to
2.0; the canonical cumulative migration remained byte-identical. The temporary stamp was not committed.Checks
origin/mainat62beb8c705d424d8e8cd12931d456f9be5f21e56after chore: retire pre-2.0 benchmark suite #187 landed;python3 devel/scripts/test_release_stamp.py -v: 14 passed (all 11 original tests plus three focused regression/hardening tests);v2.0-beta1tag/payload identity: accepted;v2.0/2.0identity: accepted;git diff --check: clean;Final landing rebase and verification
Hand-rebased onto current
mainatbfde011after #192. Exact merge candidate:eba138f9408fd33f38065abaff73eb7024daec0f..github/workflows/test.yml; it applied text-clean and retains all 848 inline assertions, PG19beta2, the release: keep compacted query attribution honest #198/release: keep stale rollups honest without losing fast path #199 extracted gates, and every release: add behavioral feature-gate coverage #192 feature/degraded surface. The workflow is 509,333 bytes, below GitHub’s 512,000-byte limit.v2.0/ payload2.0; the shippedv2.0-beta1identity passes; matchingv2.0.0is rejected. This PR does not stamp or tag the final release and changes no released SQL.X.Yline, and a final shipped payload requires a connected development migration. After promotion,sql/ash-install.sqlmust also name the released migration graph head, so compatibility shims cannot mask an omitted edge.2.1development installer over a graph ending at2.0, a same-line lone installer after final2.0, and a promoted2.1installer without a2.0→2.1migration each failed their new regression withSystemExit not raised; the old helper emitted/includes or accepted the chain. The negative fixtures require exactly empty stdout.upgrade-chainpasses all nine selected steps, including the pinned actual-v1.5 wrapper and re-apply, reader-grant/least-privilege checks, config ordinals, and both fresh-vs-upgrade schema-equivalence comparisons.The eventual
v2.0release-stamp PR must still update the installer and migration’s human-readable version comments along with the three enforced SQL stamps, asdocs/RELEASE_PROCESS.mdrequires.