Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

pgevolve v1.0 charter

This document defines what pgevolve v1.0 means: the gate that triggers the 1.0 cut, the stability commitments that hold across v1.x, the quality bar that every release meets, the Postgres-version support window, the cadence, and the parking lot of items deferred past 1.0.

The charter is living-until-1.0. At the 1.0 cut its sections either retire (the gate-tracking ones) or get partially merged into CONSTITUTION.md (the stability commitments + cadence rules).

Design rationale and the brainstorm transcript live at superpowers/specs/2026-05-28-v1-charter-design.md.


§1. What v1.0 means

A release of pgevolve where the project commits, in writing, to:

  • a defined surface that won't break in the v1.x line,
  • a defined quality bar that every release meets,
  • a defined Postgres-version support window that rolls with the upstream EOL schedule.

The 1.0 cut happens when both of the following are true:

  1. Feature checklist complete (§4) — every 📋 Planned row currently in spec/roadmap.md plus the explicit v1.0-blockers listed in §4 below are shipped.
  2. Quality gates green (§3) — the existing per-push CI gate plus a new nightly proptest soak have been running clean for at least 30 consecutive days.

The maintainer cuts the 1.0 release manually. No formal RC cycle (per the "ship-when-ready" cadence in §5); the 30-day clean-CI window functions as the de-facto RC.


§2. Stability commitments

Stable in v1.x — no breaking changes without a major bump

  • pgevolve CLI: command names, flags, exit codes, argument shapes.
  • pgevolve.toml config schema.
  • On-disk plan format: plan.sql directive headers, intent.toml schema, manifest.toml schema, the BLAKE3 plan-id derivation.
  • The set of supported PG majors must include the Postgres community-supported versions at the time of each minor release (see §6).

Explicitly unstable in v1.x — can break without a major bump

  • The pgevolve-core library API. Library consumers depend on path / git deps or pin to exact patch versions. The crate's docs.rs page leads with this notice.
  • Lint rule IDs and severities — new rules may land, old rules may be removed, severities may change up or down.
  • StepKind names in plan.sql — backward-compatible additions only; renames bump major.
  • Catalog snapshot JSON schema.
  • Internal modules (anything pub(crate)).

Deprecation policy for the stable surface

Any breaking change starts with a one-minor-cycle deprecation: the old form keeps working with a stderr warning in version N, becomes a hard error in N+1. CHANGELOG notes the deprecation in N and the removal in N+1.


§3. Quality gates (gate #2 for the 1.0 cut)

All five must hold on main for 30 consecutive days before the 1.0 tag:

GateWhat it checksWhere it runs
Per-push CIcargo fmt --check, clippy -D warnings, cargo doc -D warnings, cargo deny check, lib tests, full conformance suite on PG 14/15/16/17/18.github/workflows/ci.yml on every push
Property-test soak (nightly)The full Tier-5 property-test set at PROPTEST_CASES=5000 per PG major.github/workflows/soak.yml cron (already exists; will bump cases to 5000 and add a 1.0-readiness check that flips green/red based on the most recent 30 days of soak runs)
Cargo deny advisoriesZero open advisories for ≥ 7 days before the tagper-push + nightly
GH Actions disk-spaceThe PG-matrix conformance job survives without no space left on device (the v0.3.8 flake)per-push; runner-cleanup step OR larger runner
Cargo doc cleanNo broken intra-doc links across the workspaceper-push (enforced since v0.3.8)

Out of scope for the 1.0 gate: mutation testing (cargo-mutants), fuzzer (cargo-fuzz), code-coverage badges, perf benchmarks. Each gets its own follow-up brainstorm if/when desired.

Operational definition of "30 consecutive days clean"

  • The most recent 30 days of pushes to main had all required CI jobs end in success on first attempt (reruns count against the streak — the v0.3.8 disk-space flake would have reset it).
  • Soak cron ran every night during the window with success.
  • The streak is tracked manually pre-1.0 (a one-liner check the maintainer runs before tagging). Post-1.0 we may automate.

§4. Feature completeness (gate #1 for the 1.0 cut)

Every 📋 Planned row in spec/roadmap.md must be ✅ Implemented and shipped. The v1.0 blockers:

SourceItems
v0.4.0EVENT TRIGGER, per-partition TABLESPACE, TABLE … USING access method
v0.4.1AGGREGATE, PG 18 virtual generated columns
v0.4.2TABLESPACE (cluster object), PL-language wiring → non-SQL FUNCTION bodies
v0.4.3TEXT SEARCH family
v0.5.0FDW family (FDW, SERVER, USER MAPPING, FOREIGN TABLE, IMPORT FOREIGN SCHEMA)
v0.5.1OPERATOR / OPERATOR CLASS / OPERATOR FAMILY
v0.5.2CAST
v0.5.3Recursive views (WITH RECURSIVE) — promoted from "🔮 Future" to a v1.0 blocker. Requires cycle-aware dep-graph handling.

That's 12 sub-spec slots across 8 minor releases. Every row is independent (modulo declared dep edges in the roadmap). The order is fixed; the timing slips.

The roadmap document owns the slotting + dep-edge analysis. The charter just lists the items.


§5. Cadence + versioning

Post-1.0, the rhythm stays the same as today: ship-when-ready, no time-boxed schedule. Each release is a minor (new feature) or patch (bugfix). pgevolve commits to main only — no release branches — so every release tag points at a commit on main that passed the per-push CI gate.

Versioning rules

  • Major bump (v1 → v2): only when a breaking change to the stable surface (§2) is unavoidable. Likely never needed in 2026; pgevolve will plan to ship v1.x for the indefinite future.
  • Minor bump (v1.N → v1.N+1): new object kind, new lint rule, new CLI subcommand, new config key, new PG major support.
  • Patch bump (v1.N.M → v1.N.M+1): bug fixes only. The v0.3.8 → v0.3.9 emergency-fix flow is the patch template.

Release ceremony

Codified in ../CLAUDE.md directive 11: push main, sign + push tag, wait for full 5-PG-major CI green, then cargo publish and cargo yank the prior version if it had a shipped bug. This rule is binding for every release, v0.x and v1.x.


§6. Postgres-version support commitment

v1.0 supports every Postgres major version supported by upstream at the time of the v1.0 release. The current set is PG 14–18. The version window rolls automatically:

  • When a PG major reaches upstream EOL, the next minor release of pgevolve drops support and removes its conformance fixtures. Each removal lands in its own commit tagged chore(eol): drop PG X. The CHANGELOG explicitly calls out the drop.
  • When a PG major is released (e.g., PG 19 in late 2026), it's added in the next minor release of pgevolve after the corresponding catalog-query work lands. The v0.3.6 release ("PG 18 catalog support") is the precedent.
  • Per-version code paths are marked // PG X+ only at the call site so the EOL-drop is a mechanical grep + delete.

No LTS branch. Bug fixes target current main only. Anyone needing a fix on an older minor cuts their own patch.


§7. Explicitly post-1.0 (parking lot)

These are tracked but won't gate v1.0:

ItemWhy post-1.0
Library API stability for pgevolve-coreTied to a clear set of external consumers materializing first.
pgevolve-core re-export polish / typed errors at the public boundarySame.
Partition pruning at plan timeOptimization, not correctness.
SECURITY LABEL integrationUsed primarily by SE-Linux; low demand.
Security-barrier / leakproof per-function flag reviewLands alongside finer-grained policy review.
RULE, BASE TYPE, INHERITS, DETACH PARTITION CONCURRENTLYAlready ⛔ Not planned — kept here as "stays out".
Mutation testing, fuzzer, perf benchmarksQuality investments deferred per §3.
Distribution surface beyond cargo install (Homebrew, Docker, GH Releases binaries)Picked up once user-facing demand justifies.
Explicit rename support (a -- @pgevolve rename old -> new directive for columns / renamable objects)Renames are a bounded future feature; until then they are a documented limitation (§8). Deferred per the 2026-06 architecture review.
Full expression/body normalization (commutative-operand sorting, deep paren-folding)Subtle and partly redundant with the pg_query deparser; the common-case qualifier-recursion fix ships for 1.0, the hard cases are a documented limitation (§8). Deferred per the 2026-06 architecture review.
Full explicit type-dependent recreation (DROP each dependent + recreate views/functions, replacing the type DROP … CASCADE entirely)The 1.0 work (Phase 4) makes the CASCADE auditable — the plan names every dependent it will destroy — but keeps the gated CASCADE teardown. The larger recreation engine (which still cannot save dependent column data on an incompatible type change) is deferred.

The charter is amendable: items can move from post-1.0 into the active checklist (§4) with a CHANGELOG note. Items can also move out of the checklist if the maintainer judges them not v1.0-blocking, with a CHANGELOG note.


§8. Known limitations at 1.0

These are accepted behaviors at 1.0 — not bugs, and not gating items. Each is documented so users know the boundary; the corresponding future work (where any) lives in the §7 parking lot. All resolved in the 2026-06 architecture review.

LimitationBehaviorWhy accepted
Column / object renameA rename is diffed as DROP-old + ADD-new and flagged with a data-loss warning; the operator must intervene.The prime directive (no silent data loss) is preserved by the warning. Explicit rename is a bounded future feature (§7), deliberately not built for 1.0 to keep the core simple.
Column reorderUnsupported; column order changes are not planned.Reordering requires a full table rewrite — prohibited for data-bearing tables (Constitution §11) — and column order rarely carries logical meaning.
Expression-equivalence edge casesBoolean operands in a different order (a AND b vs b AND a), differing parenthesization, or an unnamed expression column in a view SELECT (SELECT 1pg_get_viewdef renders 1 AS "?column?") may produce a spurious (no-op) diff on some views/expressions. The common multi-table / subquery qualifier cases are normalized for 1.0; name view expression columns to avoid the ?column? case.The failure direction is always safe — a spurious recreate, never data loss. Full normalization is deferred (§7) as subtle and partly redundant with the deparser.
Extension replacement CASCADE not enumeratedDROP EXTENSION … CASCADE (emitted when an extension must be dropped+recreated) silently destroys objects depending on what the extension provides; the destructive warning says so generically but cannot name them.pgevolve manages the extension declaration, not its provided objects / membership (that's pg_depend data outside the managed model), so the dependents aren't enumerable. The operator must review manually.