# Release Notes

{/* Canonical public URL: /release-notes. Version headings are stable history anchors. */}

Release notes are ordered newest first.

Each release documents compatibility, migration, artifact/rebuild impact, and
rollback behavior according to the public
[Versioning And Compatibility](./user_guide/versioning-and-compatibility) policy.
Maintainers use the [release-note template](./contributor_guide/release-note-template)
so these sections remain explicit.

| Release history |
|---|
| [v1.1.0](#v1-1-0-pggraph-caller-scoped-rls-and-safe-replacement) |
| [v1.0.0](#v1-0-0-pggraph-production-release) |
| [v0.1.8](#v0-1-8-named-graphs-and-production-release-hardening) |
| [v0.1.7](#v0-1-7-durable-projection-operations) |
| [v0.1.6](#v0-1-6-gql-path-patterns-and-release-reliability) |
| [v0.1.5](#v0-1-5-gql-mutable-projection-stabilization) |
| [v0.1.4](#v0-1-4-pgxn-distribution) |
| [v0.1.3](#v0-1-3-structured-filters-and-architecture-clarity) |
| [v0.1.2](#v0-1-2-alpha-hardening-follow-up) |
| [v0.1.1](#v0-1-1-alpha-hardening-critical-paths) |
| [v0.1.0](#v0-1-0-initial-alpha) |

## v1.1.0: pgGraph Caller-Scoped RLS And Safe Replacement

pgGraph 1.1 makes PostgreSQL source-table RLS authoritative for graph topology,
hardens projection replacement against cancellation, reduces query-start
catalog work, and adds relationship-typed shortest paths. It supports
PostgreSQL 14 through 18 and preserves the stable 1.0 SQL result shapes.

### Security Changes

- `graph.traverse()`, `graph.connected_components()`, and
  `graph.component_stats()` now execute as `SECURITY INVOKER`. Hydration and
  later source-table visibility probes see the outer application role.
- Selected/named-graph catalog access remains behind pinned, caller-authorizing
  `SECURITY DEFINER` mediators. No Rust user-ID switching is used.
- Runtime status rows are filtered to readable graphs. Selected-graph artifact
  and build-resource telemetry requires graph `admin`; cluster generation and
  backend resource telemetry requires graph-schema administration.
- Raw build and maintenance job tables no longer grant `PUBLIC` reads. Their
  status APIs use pinned caller-authorizing mediators, and heartbeat mediators
  no longer accept caller-supplied generations or watermarks.
- Status counts remain physical projection totals. They are not
  source-table-RLS-filtered query results.
- Every topology-producing surface enforces caller visibility before topology
  becomes observable. Hidden seeds and targets behave as nonexistent; hidden
  intermediates and relationship rows do
  not affect reachability, paths, costs, components, statistics, aggregation,
  GQL/Cypher matching, or mapped-write target selection.
- `graph.rls_mode = 'enforce'` is the default. The superuser-only
  `legacy_bypass` value is a temporary compatibility escape hatch.
  `graph.allow_rls_tables` remains accepted as a deprecated no-op.

### Reliability And Query Startup

- Build, vacuum, maintenance rebuild, compaction, repair, and durable sync
  ingestion publish only a fully validated generation. Cancellation before
  publication retains the previous generation and reconciles or removes only
  the recorded unpublished candidate. Persisted low-memory replacement first
  proves that the serving generation is reloadable.
- The playground fully qualifies Docker Hub base images for Podman, reuses an
  already-satisfied virtual environment without requiring `sfw`, resolves
  Python shims before venv creation, deduplicates Panama nodes, scopes
  `statement_timeout`, caches graph initialization, and pins its data-frame
  stack.

- Query initialization now returns one owned state containing selected-graph
  metadata, registered tables and relationships, filter columns, catalog
  fingerprint and drift status, sync mode, and applicable source relation
  OIDs.
- Pending-sync and high-watermark checks consume that state through
  caller/graph-bound, cancellation-safe mediators. Automatic pending-sync
  replay also reuses it for log reads, durable ingestion, legacy replay, and
  fingerprint installation instead of loading the registration catalog again.
  Per-statement ACL, schema-drift, freshness, and sync checks remain enabled.

### Paths And Compatibility

- New overloads restrict unweighted and weighted shortest paths by
  `edge_types text[]`. Existing four-, five-, and six-argument calls retain
  their meaning, including legacy calls with an untyped `NULL` in the
  `max_depth` position.
- The `1.0.0 -> 1.1.0` extension update preserves extension catalogs, source
  rows, function ownership, explicit grants, existing signatures, and result
  shapes. Existing v6 artifacts load without a blanket rebuild.
- An RLS-active relationship mapping whose artifact lacks a usable durable
  source identity fails closed with SQLSTATE `55000`, diagnostic `PG023`, and a
  rebuild hint. A successful `graph.build()` repairs that targeted compatibility
  condition.
- In-place downgrade is not supported. Rollback restores the pre-upgrade
  PostgreSQL backup with the matching 1.0.0 package; installing a 1.0 shared
  library over 1.1 catalogs or artifacts is unsafe and unsupported. After a
  logical restore, reset and re-register the source relations and rebuild the
  derived projection because relation OIDs are database-local.

### Performance

- Query startup reuses one selected-graph/catalog state throughout freshness,
  tenant, filter, hydration, and sync decisions. The fixed-work query-start
  benchmark reduced median traversal setup latency by 21.5% versus the 1.0
  baseline.
- On the no-RLS path, visibility construction returns before source-row scans
  or graph-sized bitmap allocation. The unrestricted visibility benchmark measured a 1.5%
  median and 3.6% p95 change versus the query-start baseline, inside the 5%/10%
  release budget.
- Relationship-type filtering added no measurable median regression in the
  recorded fixed-work shortest-path benchmark. These measurements are
  environment-specific evidence, not universal latency guarantees.

### Operational Notes

- A mapped artifact is copied into a private anonymous mapping in each backend.
  Its physical pages are not shared across backends through the OS page cache;
  plan resident memory as artifact size multiplied by concurrent loaded
  backends plus query and maintenance workspace.
- See [Versioning And Compatibility](./user_guide/versioning-and-compatibility)
  for the exact update, rebuild, and backup-restore rollback procedure.

## v1.0.0: pgGraph Production Release

`v1.0.0` is pgGraph's first production release and supports PostgreSQL 14
through 18. PostgreSQL tables remain the source of truth, and pgGraph's graph
indexes and projections can be validated and rebuilt from them.

### Supported Surface

- The exact SQL function, configuration, diagnostic, and bounded GQL read/write
  profiles are generated and drift-checked. Full ISO GQL, full openCypher, and a
  public SQL/PGQ `GRAPH_TABLE` surface are not claimed.
- Named graphs, PostgreSQL-backed mapped writes, durable synchronization,
  resource-governed traversal and analytics, persisted generation recovery,
  maintenance jobs, and operator diagnostics are supported within the public
  limits documentation.
- Standard PostgreSQL SQLSTATEs are paired with stable `PGxxx` diagnostics in
  `DETAIL`. Applications migrating from alpha builds must update any code that
  depended on the earlier nonstandard SQLSTATE mapping.

### Alpha Migration And Rebuild

The supported transition from `v0.1.8` is source-preserving, not an in-place
catalog or binary upgrade. Back up the database, record graph registrations,
disable writers and schedulers, remove the alpha extension, install 1.0.0,
reapply registration, and rebuild from the PostgreSQL source tables. Before
using `DROP EXTENSION graph CASCADE`, inventory application objects that depend
on extension functions or types; `CASCADE` removes those dependents as well as
extension-generated sync objects.

Alpha `.pggraph` files, projection manifests, and segments are not loaded as a
1.0 compatibility promise. Rebuild them with the 1.0 engine. The 1.0 base
artifact format is v6 and mutable projection metadata is checksummed and
generation-addressed.

### Rollback

Do not install an alpha binary over 1.0 catalogs or artifacts. Before cutover,
retain a logical backup plus the matching alpha package and registration
inventory. Rollback restores that backup into a clean database using the alpha
package; source rows are authoritative, and derived graph state is rebuilt.

### Security, Resources, And Deprecations

- Extension and generated trigger security-definer boundaries use a pinned
  `pg_catalog, pg_temp` search path, preserve caller-role ACL/RLS checks, and
  reject unsafe catalog/source lock combinations before publication.
- Build, load, query, hydration, synchronization, compaction, and supported
  analytics enforce documented memory, work, row, disk, file, and elapsed-time
  limits. Rejected work does not replace the last validated generation.
- The alpha `graph.oom_action` and `graph.allow_unsafe_oom_actions` settings are
  accepted as read-only compatibility aliases throughout 1.x. They do not
  authorize unsafe allocation behavior and should be removed from new
  configurations.

### Release Validation And Distribution

The release was validated with retained RC/full-matrix evidence, clean PostgreSQL
14–18 source-package installation, the signed alpha migration fixture,
backup/restore and crash recovery, concurrency and transaction gates, resource
measurements, sanitizers, fuzz/Miri checks, and packaged quickstart and
playground examples. The source bundle contains one commit-bound PGXN ZIP,
SPDX 2.3 SBOM, provenance, manifest, and complete SHA-256 set. Publication must
consumed those exact prepared bytes after signed-tag verification without
rebuilding the archive.

## v0.1.8: Named Graphs And Production Release Hardening

`v0.1.8` adds named graph administration, graph-scoped catalogs, hosted
maintenance jobs, relationship creation, and stricter query-surface boundaries.
pgGraph can now keep multiple registered graph definitions in the same
extension schema, apply graph-specific grants and quotas, scope builds and sync
replay to the selected graph, and expose enough runtime state for operators to
load, unload, inspect, and maintain those graphs without falling back to raw
catalog writes.

This release also expands the mutable GQL write surface with registered
relationship creation and row hydration, while keeping PostgreSQL source tables
authoritative for graph mutations. Capability checks for openCypher and
SQL/PGQ are now explicit, so unsupported syntax is rejected with clearer
compatibility guidance instead of drifting into partial behavior.

The final release candidate hardens restricted-role SQL behavior, refreshes the
Rust and pgrx release toolchain, and documents the full release handoff from
gate evidence through signed tags and package publishing.

### Highlights

- Added a durable named-graph catalog with graph creation, selection,
  description, residency, grants, quotas, and metadata inspection APIs.
- Scoped node registrations, relationship registrations, filter columns, build
  jobs, maintenance jobs, sync policies, and sync replay by graph identity.
- Added runtime graph loading and unloading controls so operators can manage
  selected graphs and inspect active runtime state.
- Added graph grants and quota policy enforcement for visibility, build,
  sync, mutation, and administration paths.
- Added hosted sync-policy jobs, hosted due-job runners, and an internal due
  job worker so scheduled maintenance can run through graph-scoped job state.
- Added graph-aware discovery and direct identity lookups for registered
  labels and relationships.
- Added GQL `CREATE` support for registered relationships, including source-row
  inserts, transaction-local visibility, and hydrated relationship rows in
  query results.
- Added graph-scoped projection and sync behavior so replay, dirty-range
  ingest, copy-on-write compaction, and runtime selection ignore unrelated
  graph state.
- Added explicit openCypher and SQL/PGQ capability boundaries with clearer
  unsupported-feature reporting and compatibility corpus coverage.
- Hardened named-graph catalog access so internal graph catalogs are mediated
  through SQL APIs and caller-role visibility checks.
- Hardened restricted-role graph access so selected-graph metadata, sync status,
  and runtime state can be resolved through controlled definer boundaries while
  preserving caller-role graph grants and PostgreSQL source-table ACL/RLS
  checks.
- Refreshed the release toolchain to Rust 1.96 and pgrx 0.19.1, with matching
  Docker, Nix, Cargo, installation, and PGXN source-build documentation.
- Added a contributor release-gate checklist that records required gates,
  environment prerequisites, opt-in gates, evidence capture, signed tagging,
  package validation, and prepare/publish ordering.

### Named Graph Administration

Named graphs move pgGraph beyond one implicit default graph. Operators can
create graph definitions, select the active graph for a role, list graph
metadata, configure residency, grant graph-level capabilities, and set build or
storage quotas. Registration APIs now attach tables, relationships, filter
columns, sync policies, and build state to a graph ID, while existing default
graph behavior remains available for simple installs.

The graph-scoped catalog layer also changes runtime behavior. Build operations,
auto-discovery, traversal, GQL queries, sync replay, projection ingest, and
maintenance jobs now resolve the caller's selected graph and reject access when
the role lacks the required graph privilege. Runtime status APIs report graph
identity and residency state so loaded graph engines are no longer treated as a
single global slot.

### Hosted Maintenance And Sync

`v0.1.8` adds graph-scoped job tables and scheduler entry points for hosted
maintenance. Sync policies can create due jobs, due-job runners can claim and
execute graph work, and Docker installs continue to schedule
`graph.run_scheduled_maintenance()` through `pg_cron`. The same job model can
be used by external schedulers in non-Docker deployments.

Build jobs and maintenance jobs now include graph identity, advisory-lock
coverage was updated for graph-scoped work, and sync replay ignores source
changes that belong to other registered graphs. Projection maintenance paths
also preserve graph scope when ingesting dirty ranges or compacting
copy-on-write state.

### GQL And Compatibility

The GQL mutable write path can now create registered relationships. Relationship
creation resolves mapped endpoint rows, inserts through PostgreSQL DML, exposes
transaction-local changes to subsequent graph reads, and returns hydrated
relationship records. Direct identity lookups support the new row hydration
paths without making graph artifacts a second source of truth.

The release also makes compatibility boundaries more explicit. The openCypher
preview accepts only the subset that maps cleanly to pgGraph's GQL IR, and the
SQL/PGQ adapter documents supported typed-hook behavior separately from
PostgreSQL's future SQL parser integration. Unsupported features now fail with
clearer errors and capability metadata.

### Compatibility

The named-graph catalog adds new extension-owned tables and changes the shape
of several internal administration paths. Existing single-graph installs should
continue to use the default graph, but development databases created from older
alpha catalog layouts should be recreated before testing this release.

Source tables remain the source of truth. Graph artifacts, projection segments,
sync state, and runtime engines are still derived from PostgreSQL tables and
graph registration metadata.

`v0.1.8` raises the source-build baseline to Rust 1.96 and pgrx 0.19.1.
PostgreSQL 14 through 18 remain the supported PostgreSQL majors, with
PostgreSQL 17 as the default release-gate target.

### Release Validation

The production release candidate completed the full PostgreSQL 17 release gate,
including docs drift, dependency freshness remediation, formatting, clippy,
Rust docs and doctests, unit tests, pgrx SQL tests, cargo-deny, fuzz compile,
projection seed corpora, package validation, fresh install smoke,
SQL metadata audit, SQLSTATE/ACL boundary tests, backup/restore,
lock-regression gates, concurrency stress, synthetic release fixture,
Docker/playground validation, pgbench sync stress, GQL write lifecycle gates,
named-graph heavy gates, cross-backend durable projection checks, projection
recovery, transaction-delta lifecycle, and write predicate re-check races.

The playground release gate now treats nondeterministic demo sample hashes as
row-count assertions while retaining stable checksums for deterministic results.
This keeps the gate focused on product regressions instead of component-id or
sample-order drift across fresh builds.

## v0.1.7: Durable Projection Operations

`v0.1.7` adds the durable projection operation layer for mutable graphs. pgGraph
can now publish committed source-table changes into durable projection
segments, read those segments alongside the base CSR graph, compact accumulated
segment state, repair dirty base chunks, garbage-collect obsolete generations,
and surface operator diagnostics through SQL functions.

This release also stabilizes how GQL returns relationship values for
bidirectional edges. Bidirectional edges can still be traversed from either
endpoint, but relationship records now keep the source and target endpoint
order registered in the graph schema. That makes edge records consistent for
applications that render graph edges or inspect `_start`, `_end`, path values,
or `relationships(path)`.

### Highlights

- Added manifest-backed layered reads that merge the base CSR graph, durable
  projection segments, replacement base chunks, committed overlay rows, and
  transaction-local deltas into one traversal view.
- Routed traversal, shortest path, weighted shortest path, connected
  components, and GQL relationship expansion through the layered projection
  runtime when a graph is built with durable projection state.
- Published committed mutable-overlay changes as durable segments, so fresh
  backends can observe committed graph writes without requiring a full
  `graph.build()` rebuild.
- Added durable segment compaction, including preservation of weighted
  relationship state and rewrite support for dirty base chunks.
- Added generation heartbeats and generation-aware garbage collection so
  obsolete projection files are removed only after retained valid generations
  and active backends no longer protect them.
- Added projection recovery and repair support, including targeted base-chunk
  repair and rollback-safe full rebuild restoration.
- Added operator-facing diagnostics through `graph.projection_status()`,
  `graph.projection_gc()`, `graph.projection_repair()`, and
  `graph.active_generation_count()`, with additional durable-projection
  recommendations exposed through `graph.sync_health()`.
- Preserved registered source and target endpoints in GQL relationship values
  even when a bidirectional edge is matched through its reverse traversal path.
- Updated release automation and verification for native multi-platform Docker
  builds, package prepare/publish separation, projection fuzz seed corpora,
  crash recovery gates, Docker smoke checks, and release benchmark contracts.

### Durable Projection Behavior

Durable projections let pgGraph keep PostgreSQL source tables authoritative
while avoiding a full graph rebuild for every committed mutable change. When
durable projection mode is active, committed sync rows can be ingested into
projection segment files. Readers then combine those segment files with the
base graph and any transaction-local overlay state at query time.

The layered runtime is used across the graph surfaces that need topology reads:

- traversal APIs
- unweighted shortest path
- weighted shortest path
- connected components
- GQL relationship expansion
- query-time catch-up for mutable graph writes

Projection maintenance is now represented as explicit operations. Segment
ingestion records committed changes, compaction bounds segment fanout, dirty
base chunk rewrite repairs source-node ranges, recovery validates and restores
projection generations, and GC removes obsolete files only after retention and
active-generation checks pass.

### New SQL Operations And Diagnostics

`v0.1.7` adds and documents durable projection administration entry points:

- `graph.projection_status()` reports manifest, segment, chunk, heartbeat,
  validation, operation timestamp, and recommendation diagnostics.
- `graph.projection_gc()` runs generation-aware cleanup for obsolete projection
  files.
- `graph.projection_repair()` validates projection state and repairs targeted
  chunk damage or restores a valid full rebuild when needed.
- `graph.active_generation_count()` exposes how many active projection
  generations are protected by backend heartbeats.
- `graph.sync_health()` includes metadata-only durable projection
  recommendations without changing the core source-table sync model.

The release also adds `graph.projection_retention_generations` so operators can
control how many valid projection generations are retained before GC can remove
obsolete files.

### GQL Relationship Behavior

Before `v0.1.7`, a bidirectional edge matched through its reverse traversal
path could be returned with endpoints ordered according to the path pattern.
For example, if a relationship was registered from `account_a` to `account_b`,
a reverse traversal from `account_b` back to `account_a` could expose the
relationship value as though its start and end were reversed.

Starting in `v0.1.7`, traversal direction and relationship identity are kept
separate:

- Path matching still honors bidirectional traversal.
- Relationship values preserve the registered schema direction.
- Path values preserve the matched node order for the path, while embedded
  relationship records preserve the registered relationship direction.
- `relationships(path)` returns relationship records with stable endpoint
  orientation, even when a relationship was traversed in reverse.

The fix is applied through edge storage, persisted graph artifacts, projection
segments, transaction overlays, compaction, dirty chunk rewrite, and GQL
materialization so schema-direction relationship values stay stable across the
new durable projection paths.

### Release And Packaging

The release process was hardened alongside the projection work:

- Package publishing now separates prepare and publish modes.
- Docker release builds run natively per platform and then merge per-platform
  digests into the prepared multi-arch tags.
- Docker extension verification waits briefly before failing and prints
  container logs on failure.
- GHCR image naming is normalized to lowercase.
- The local release gate now uses the same `pg17 development` feature set as
  the maintained pgrx evidence command.
- Projection manifest and segment fuzz seed corpora can be run outside a live
  PostgreSQL backend through the release-gate script.
- Documentation now includes the Homebrew install path and expanded durable
  projection operation notes.

### Compatibility

Queries that only check reachability, filter by labels or properties, or return
node values should behave the same as before. Queries that inspect relationship
endpoint fields, compare path relationship values, or render directed edge
arrows from `relationships(path)` may observe changed output for reverse
matches on bidirectional relationships. The new output is the registered schema
direction, not the reverse path-pattern direction.

The persisted artifact formats changed for this release. Graph artifacts now
use graph format v3, and projection segments now use segment format v2, so the
schema-direction metadata can be loaded safely. Existing source tables and graph
registrations do not need to be rewritten.

### Upgrade Note

<Callout type="warning">
`.pggraph` artifacts written before `v0.1.7` must be regenerated with
`SELECT graph.build();` after upgrading. These files are derived artifacts, not
the source of truth; PostgreSQL source tables remain authoritative.
</Callout>

Regenerating the derived artifact is the intended upgrade path:

```sql
SELECT graph.build();
```

### Validation

The PostgreSQL 17 release gate passed for this release, including fmt, clippy,
documentation checks, unit tests, pgrx SQL tests, package validation, install
smoke, metadata audit, SQLSTATE/ACL boundary tests, backup/restore,
advisory-lock regression coverage, concurrency stress, projection recovery,
cross-backend durable projection checks, projection fuzz seed corpora,
playground query validation, pgbench sync stress, Docker smoke, RSS
measurement, and disposable crash recovery checks.

The release also added benchmark and contract coverage for layered BFS, GQL
relationship expansion, weighted paths, ingest publication, compaction, GC, and
repair, and was checked against the public package metadata and documentation
references for the `v0.1.7` tag.

## v0.1.6: GQL Path Patterns And Release Reliability

`v0.1.6` expands pgGraph's GQL query surface with richer path-pattern support,
safer mutable-write checks, and a stricter persisted artifact format. It also
adds release validation and packaging improvements for the `pg17` build path.

### Highlights

- Added GQL support for multi-pattern joins, including optional pattern groups,
  ordered and deduplicated join rows, and aggregate projections over joined
  paths.
- Added projection support for join aliases, relationship variables, path
  variables, and path functions such as `nodes(path)`, `relationships(path)`,
  and `length(path)`.
- Expanded wildcard path support with named wildcard path elements, fixed
  path-variable chains, bounded wildcard expansion, multi-segment wildcard
  variable-length paths, and relationship-type alternation.
- Improved wildcard path filtering so node-property predicates and wildcard
  relationship deletes work through the GQL planner.
- Rechecked mutable GQL write predicates against the affected source rows and
  rejected transaction-local traversal entry points that cannot be evaluated
  safely.
- Validated edge-table endpoints during registration so invalid relationship
  mappings fail earlier.
- Migrated persisted `.pggraph` metadata sections from `bincode 1.3.3` to
  `bincode 2.0.1` with serde support.
- Made metadata decoding reject trailing bytes instead of accepting partially
  consumed payloads.
- Refreshed release dependency pins and added release validation scripts and
  workflow coverage for packaging, source builds, install checks, metadata
  audits, and heavy test gates.

### Upgrade Note

<Callout type="warning">
`.pggraph` artifacts written before `v0.1.6` must be regenerated with
`SELECT graph.build();` after upgrading. These files are derived artifacts, not
the source of truth; PostgreSQL source tables remain authoritative.
</Callout>

Regenerating the derived artifact is the intended upgrade path for this release.

### Validation

The `pg17` release gate passed:

```bash
PG_VERSION_FEATURE=pg17 ./tests/heavy/run_release_gate.sh
```

That gate includes fmt, clippy, docs, unit tests, pgrx SQL tests, cargo-deny,
fuzz binary checks, package validation, fresh install smoke, metadata audit,
SQLSTATE/ACL boundary tests, backup/restore, advisory-lock regressions,
concurrency, synthetic smoke, rebuilt playground fixtures, pgbench sync stress,
and GQL transaction lifecycle and race scripts.

## v0.1.5: GQL Mutable Projection Stabilization

`v0.1.5` introduces pgGraph's GQL surface and the mutable projection path that
lets mapped GQL writes update PostgreSQL source rows while keeping the in-memory
graph view transactionally consistent. This release turns GQL from an internal
planning target into a documented SQL entry point, adds node and relationship
mutability through the overlay engine, and keeps the `v0.1.4` installation and
SQL function surface compatible.

### Highlights

- Added `graph.gql()` as the primary standards-oriented graph query surface for
  pgGraph, with `graph.gql_explain()` for stable plan inspection.
- Added mutable GQL support for mapped source tables, including `CREATE`,
  `MERGE`, `SET`, `REMOVE`, relationship `DELETE`, and `DETACH DELETE` paths
  backed by PostgreSQL row changes and transaction-local projection deltas.
- Preserved PostgreSQL as the source of truth for mutable graph data: GQL writes
  honor table mappings, ACL/RLS checks, tenant scope, rollback behavior, and
  overlay limits.
- Added transaction lifecycle coverage for GQL create, set/remove, delete, and
  merge race paths in the release gate.
- Made trigger sync the default sync mode, so a normal `graph.build()` installs
  source-table sync triggers and topology reads catch up to pending rows by
  default unless operators opt into `graph.sync_mode = 'manual'`.
- Upgrade note: deployments that relied on implicit manual refresh should set
  `graph.sync_mode = 'manual'` before running `graph.build()`. When trigger
  mode is active, `graph.build()` emits a warning that sync triggers were
  installed on registered source tables.
- Fixed mapped dynamic-label edge deletes so rows with `NULL` or blank
  `label_column` values fall back to the registered relationship label.
- Preserved transaction-local nodes for non-tenanted tables even when a session
  tenant scope is active, while still hiding unscoped writes for tenanted tables.
- Fixed optional aggregate semantics so `collect`, `count(expr)`, `sum`, `avg`,
  `min`, and `max` ignore JSON `null` values while `count(*)` still counts
  every input row.
- Cancelled net-neutral transaction edge deltas before overlay-cap accounting,
  avoiding false overlay-limit failures for insert/delete pairs that leave no
  pending edge.
- Normalized GQL path function names case-insensitively for `nodes(path)`,
  `relationships(path)`, and `length(path)`.
- Returned typed GQL errors for value-projection invariants instead of relying
  on internal panics.
- Decoupled variable-length path cardinality from whether the query returns a
  path value, and preserved explicit `*1..1` path-distinct matches.
- Stabilized `graph.gql_explain()` output around registered table labels and
  fixed catalog reads of `regclass` fields so explain fixtures no longer drift
  with table OIDs.
- Updated the playground release gate to rebuild the Docker image and recreate
  the playground container during the full release gate, preventing stale
  extension binaries from passing or failing the fixture suite.

### Testing

- Added regression coverage for dynamic-label delete fallback values,
  non-tenanted transaction-local node visibility under tenant scope, explicit
  single-hop variable-length path cardinality, catalog-backed explain labels,
  and playground release-gate freshness.
- Spawned a second-opinion Rust review subagent for the GQL/projection changes;
  all findings from that pass were fixed.

### Validation

The full `pg17` release gate passed, including fmt, clippy, docs, unit tests,
pgrx SQL tests, cargo-deny, fuzz binary checks, package validation, fresh
install smoke, metadata audit, SQLSTATE/ACL boundary tests, backup/restore,
advisory-lock regressions, concurrency, synthetic smoke, rebuilt playground
fixtures, pgbench sync stress, and GQL transaction lifecycle scripts:

```bash
PG_VERSION_FEATURE=pg17 ./tests/heavy/run_release_gate.sh
```

## v0.1.4: PGXN Distribution

`v0.1.4` adds PGXN distribution metadata and a top-level Makefile for
source-based installation via PGXN. It keeps the `v0.1.3` SQL contract
and adds no breaking changes.

### Highlights

- Added PGXN `META.json` distribution metadata at the repository root.
- Added a PGXN-compatible top-level `Makefile` that delegates to `cargo pgrx`.
- Added PGXN and manual source installation documentation to `README.md`,
  `README_zh.md`, and the user guide.
- Documented `PG_CONFIG` targeting and missing PostgreSQL header
  troubleshooting for source installs.
- Prepared pgGraph for source-based PGXN release.

### Validation

Run the PGXN metadata validation (`cargo install pgxn_meta --locked`):

```bash
pgxn_meta
```

Run the PGXN-style build flow:

```bash
make
make installcheck
```

## v0.1.3: Structured Filters And Architecture Clarity

`v0.1.3` adds structured traversal filter helpers, removes the legacy raw-filter
parser, refactors internal filter and sync state, tightens engine encapsulation,
and documents pgGraph's architecture tradeoffs. It keeps the `v0.1.2` SQL
contract and adds no breaking changes.

### Highlights

- Added six structured traversal filter helpers for membership, text, and null
  predicates: `graph.in()`, `graph.not_in()`, `graph.contains_text()`,
  `graph.prefix_text()`, `graph.is_null()`, and `graph.is_not_null()`.
- Removed the legacy raw-filter parser from all paths including development,
  tests, and fuzzing; structured JSONB filters are now the only supported
  traversal filter boundary.
- Refactored `FilterOp` into a `FilterOp { column_idx, condition }` struct with
  a separate `FilterCondition` enum so column targets and predicate conditions
  are represented independently.
- Encapsulated sync row replay behind a typed `SyncRowOperation` helper so node
  insert, update, delete, and truncate are resolved once and applied in order.
- Routed mmap-backed node mutations through engine helpers that materialize
  borrowed arrays before in-place mutation.
- Narrowed all `Engine` store, sync, resolution, mmap, and status fields from
  `pub` to `pub(crate)`, establishing the engine as a crate-internal boundary.
- Added a new architecture tradeoffs documentation page covering pgGraph's
  design philosophy, read-only mmap positioning, and SQL/PGQ relationship.

### New Features

- `graph.in(column, values)` — membership filter accepting a JSONB array of
  values. Typed pushdown covers `u32`, `i64`, `bool`, text token, and UUID
  columns.
- `graph.not_in(column, values)` — negative membership filter with the same
  typed pushdown coverage.
- `graph.contains_text(column, value)` — substring filter for dictionary-encoded
  text columns. Pushed down against the text dictionary at traversal time.
- `graph.prefix_text(column, value)` — prefix filter for dictionary-encoded text
  columns.
- `graph.is_null(column)` — explicit NULL check filter. Also works through the
  existing `eq` operator with a NULL value, but provides clearer intent.
- `graph.is_not_null(column)` — explicit NOT NULL check filter.

All six helpers produce the same structured JSONB format consumed by
`graph.traverse(filter := ...)` and `graph.all()`.

### Internal Changes

- **Filter pushdown refactor**: `FilterOp` is now a struct holding `column_idx`
  and a `FilterCondition` enum. All existing pushdown variants (`Eq`, `Neq`,
  `Gt`, `Between`, `EqI64`, `EqBool`, `EqToken`, `EqUuid`, `IsNull`, etc.)
  moved into `FilterCondition`, with new membership (`In`, `NotIn`, `InI64`,
  `NotInI64`, `InBool`, `NotInBool`, `InToken`, `NotInToken`, `InUuid`,
  `NotInUuid`) and text (`ContainsToken`, `PrefixToken`) variants added.
- **Hydration filter operators**: `HydrationFilterOperator` gained `In`,
  `NotIn`, `Contains`, `Prefix`, `IsNull`, and `IsNotNull` variants for
  source-row recheck of filters that cannot be pushed down.
- **Structured filter validation**: `validate_structured_operator_shape()` now
  runs unconditionally for all filters, not only for columns with a resolved
  column type. Added validation for `contains`/`prefix` (must be text),
  `in`/`not_in` (must be array), and `is_null`/`is_not_null` (must be null or
  true).
- **Legacy raw-filter removal**: Deleted the `parse_condition` fuzz target
  and its `Cargo.toml` entry. Removed the development-only raw-filter parser
  and associated unit tests from `filter_index.rs`.
- **Sync row replay**: Introduced `SyncRowOperation` enum with `Insert`,
  `Update`, `Delete`, and `Truncate` variants. Each sync log entry is parsed
  into a typed operation before the engine applies ordered node mutations, edge
  overlays, tenant updates, and filter index refreshes.
- **Engine encapsulation**: All `Engine` fields (`node_store`, `edge_store`,
  `reverse_edge_store`, `filter_index`, `edge_type_registry`, `built`,
  `sync_status`, `resolution_store`, `resolution_delta`, `edge_buffer`,
  `is_read_only`, `read_only_reason`, `applied_sync_id`, `needs_vacuum`,
  `needs_rebuild`, `schema_state`, `table_membership`, `tenant_membership`,
  `tenanted_table_oids`, etc.) changed from `pub` to `pub(crate)`. Helper
  structs `ResolutionStore`, `MmapResolutionState`, and `EdgeMutation` fields
  also narrowed to `pub(crate)`.
- **Resolution index tests**: Added `resolve()` coverage for `ResolutionIndexBuilder`
  and `len()` coverage for `ResolutionDeltaIndex`.
- **Test helper fix**: Restored `ensure_current_graph` visibility for
  `pg_test` so pgrx SQL integration tests continue to compile after the
  facade module refactor.

### Documentation

- Added `docs/contributor_guide/architecture-tradeoffs.mdx` documenting pgGraph's
  design philosophy, mmap tradeoffs, and SQL/PGQ positioning. Linked from the
  docs overview, contributor guide, and quick-links navigation.
- Clarified mmap as read-only derived artifact mapping across `build-and-persistence`,
  `limitations-and-fit`, `roadmap`, `memory-model`, and `index` docs. Added
  callouts explaining that `.pggraph` files are not PostgreSQL buffer-pool
  replacements.
- Updated `querying.mdx` with structured filter examples using `graph.in()`,
  `graph.is_not_null()`, and related helpers. Added search index guidance for
  case-insensitive and trigram queries.
- Updated `schema-registration.mdx` with auto-discovery text property boundaries,
  manual registration examples, and filter-column registration guidance.
- Updated `api-reference.mdx` with the new filter helper function entries.
- Updated `configuration.mdx` with GUC enum compatibility policy for typed
  string settings with aliases.
- Updated `quickstart.mdx` with quickstart mode documentation.
- Updated `known-issues.mdx`: added 13 closed items under P1/P2/P3 and removed
  all previously tracked P2 rows (auto-discovery text, structured filter
  operators, legacy raw filters, case-insensitive search, GUC enum behavior)
  now that structured filters cover text, membership, range, null, and prefix
  semantics. Moved the pgrx SQL test module layout note into contributor
  testing documentation.
- Updated `roadmap.mdx` to reflect cleared P2 and P3 backlogs and added SQL/PGQ
  comparison note under benchmark plans for PostgreSQL 19.
- Updated `README.md` and `README_zh.md` with version `0.1.3` badges and
  refreshed project descriptions.

### Validation

Focused validation for this branch included local documentation reference checks
(`scripts/check_doc_references.py`), targeted Rust unit tests
(`cargo test --features pg17`), clippy gate
(`cargo clippy --features pg17 --lib -- -D warnings`), and pgrx pg_test compile
checks (`cargo test --features pg17,pg_test --lib --no-run`).

Run the full release gate before publishing binary packages for `v0.1.3`:

```bash
PG_VERSION_FEATURE=pg17 ./tests/heavy/run_release_gate.sh
```

### Commit Coverage

This release covers 14 commits on the `alpha-hardening-critical-paths`
branch, from `f88d9cb` (fix: restore pg facade test helpers) through `f3c5cd0`
(build: bump version to 0.1.3).

## v0.1.2: Alpha Hardening Follow-Up

`v0.1.2` finishes the highest-priority follow-up work from the alpha hardening
pass. It keeps the `v0.1.1` SQL contract, improves several hot query paths, and
adds release-gate coverage for a background-job failure case that was previously
only exercised by real workers.

### Highlights

- Failed build and maintenance jobs now use the same durable failure-recording
  path in development test runners and background workers. The advisory-lock
  regression gate now verifies that failed job rows do not remain in `running`.
- Source-row search avoids repeated query normalization and table label setup
  while rechecking candidate rows.
- Aggregation hydration reuses borrowed parent-path rows and keys hydrated
  all-path rows by table, reducing clone-heavy lookup work.
- Traversal metadata is now adaptive: dense maps are still used for normal
  high-coverage traversals, while sparse parent/depth maps are used for
  low-visit-budget traversals on large graphs.

### Performance

Internal benchmark runs for the changed paths showed:

| Area | Before | After |
|---|---:|---:|
| Source search, warmed | 0.14s | 0.08s |
| Aggregation hydration | 8.33s | 6.32s |
| Dense-path traversal internals | 0.37s | 0.11s |

### Validation

The `pg17` heavy release gate passed with fmt, clippy, docs, unit tests, pgrx SQL
tests, cargo-deny, fuzz check, package validation, fresh install smoke, metadata
audit, SQLSTATE/ACL boundary tests, backup/restore, lock regressions,
concurrency, synthetic release smoke, and pgbench sync stress:

```bash
PG_VERSION_FEATURE=pg17 DB_PREFIX=pggraph_release_prep3 RUN_PLAYGROUND=0 ./tests/heavy/run_release_gate.sh
```

Synthetic smoke built `50,000` nodes and `150,889` edges in `1775 ms`, queried
in `43 ms`, and wrote the expected `.pggraph` artifact. The pgbench sync stress
run completed `3045` transactions with `0.000%` failures.

The Docker-backed playground gate also passed, validating all `26` Streamlit
playground query examples against the prepared Panama dataset:

```bash
PGGRAPH_PLAYGROUND_YES=1 PG_VERSION_FEATURE=pg17 ./tests/heavy/playground_release_gate.sh
```

The sandbox Panama benchmark gate passed as well:

```bash
./sandbox/run_benchmarks.sh panama --yes
```

Observed Panama evidence: `2,016,523` source nodes, `5,802,586` graph edges,
`63.20s` load time, `60.01s` build time, `185.50 MB` memory used, and a
`2048 MB` memory limit. Hot median query timings were `29.064 ms` for status,
`83.2705 ms` for entity search, `107.39 ms` for depth-2 traversal, `3.1295 ms`
for shortest path, `147.9435 ms` for component stats, and `572.17 ms` for
largest component.

Finally, the focused background-job advisory-lock regression gate passed after
the test-runner failure-recording fix:

```bash
PG_VERSION_FEATURE=pg17 DBNAME=pggraph_release_prep_background_lock ./tests/heavy/background_job_lock_regression.sh
```

## v0.1.1: Alpha Hardening Critical Paths

This release hardens pgGraph's alpha SQL contract, sync behavior, persistence
path handling, Docker operations, release gates, playground coverage, and
supply-chain policy.

<Callout type="warning">
  This release includes SQL contract changes. Review the breaking changes before
  upgrading applications that call `graph.weighted_shortest_path()`, inspect
  status rows, or branch on pgGraph SQLSTATEs.
</Callout>

### Breaking Changes

- `graph.weighted_shortest_path()` now returns one SQL row per path step instead
  of the previous compact single-row payload. The row shape is `step`,
  `node_table`, `node_table_name`, `node_id`, `edge_label`, `edge_weight`,
  `step_cost`, and `total_cost`. Consumers using the old `path_nodes` /
  `total_cost` single-row result must update their queries.
- `graph.status()` now includes `read_only_reason`.
- `graph.sync_health()` is new and includes scheduler/operator fields,
  including `read_only_reason`.
- `graph.build_status()` and `graph.maintenance_status()` now include
  `progress_phase` and `progress_message`.
- Sync mutations against an already read-only engine now report `PG012` instead
  of reusing `PG008`.

<Callout type="info">
  Docker users should recreate existing pgGraph Docker volumes to pick up the
  new init SQL and `pg_cron` schedule. Existing initialized PostgreSQL volumes do
  not rerun files from `/docker-entrypoint-initdb.d/`.
</Callout>

### New Features

- Added `graph.sync_health()` for scheduler-friendly sync and maintenance
  diagnostics: `query_freshness`, `sync_batch_size`, sync high-water state,
  pending rows, edge-buffer usage, rebuild/vacuum needs, read-only state, and
  maintenance recommendations.
- Added `graph.run_scheduled_maintenance()` as an admin-only scheduler entry
  point. It applies pending sync when safe, then starts concurrent maintenance
  when needed.
- Added durable build and maintenance progress diagnostics through
  `progress_phase` and `progress_message`.
- Added `graph.query_freshness` GUC for topology reads. Supported values are
  `apply_pending_sync`, `off`, and `error_on_pending`.
- Added `graph.sync_batch_size` GUC to bound internal sync replay batches.
- Added a heavy read-latency benchmark for sync backlog scenarios.
- Added a heavy playground release gate that imports the same query catalog used
  by the Streamlit sidebar and validates fixed Panama dataset result summaries.
- Added a dependency update checker that reports Cargo, Python, Docker, and Nix
  flake GitHub input update candidates without automatically applying them.

### Behavior Changes

- Topology reads now apply pending trigger sync by default before reading graph
  topology. This covers traversal, shortest path, weighted shortest path,
  traverse search, component APIs, aggregation, and path-count estimates.
- `graph.aggregate()` and `graph.path_count_estimate()` now honor
  `graph.query_freshness`; they no longer bypass pending-sync policy.
- `graph.search()` remains a source-table search path and is not treated as a
  topology read.
- Sync replay is bounded by `graph.sync_batch_size` and captures high-water
  marks to avoid unbounded replay.
- Legacy `_sync_buffer` replay now scans forward through a captured high-water
  mark. Permanently failing rows remain buffered, but no longer block later
  valid rows.
- Query-time sync catch-up fails closed when configured with
  `error_on_pending`.

### Fixes

- Fixed edge replay capacity handling so high-fanout sync rows reserve
  edge-overlay capacity before mutating state, avoiding partial edge writes.
- Fixed edge-store construction to reject out-of-range endpoints instead of
  silently dropping corrupt edges.
- Removed production panic paths from edge-store constructors.
- Fixed JSON hydration comparisons so large integers preserve exactness and JSON
  strings no longer match numeric values implicitly.
- Hardened persisted artifact loading against corrupt primary-key bytes before
  mmap stores are built.
- Fixed durable graph artifact path resolution for normal PostgreSQL backends
  where `PGDATA` is not exported, using PostgreSQL's backend `DataDir` pointer
  without requiring privileged `SHOW data_directory`.
- Hardened source-search SQL by binding predicates through SPI parameters.
- Fixed token-search SQL candidate selection so per-table pagination does not
  hide valid Rust-verified rows.
- Fixed source-search candidate scan bounds, dedupe stability, and pagination
  semantics.
- Improved memory/status accounting with store-specific heap estimates and a
  conservative logical floor.
- Preserved `PG008` for edge-buffer capacity breaches and uses `PG012` for later
  read-only sync mutations.
- Added missing `SAFETY:` comments on test-only mmap unsafe blocks so clippy
  release gates pass.

### Docker And Ops

- Docker image now installs `postgresql-17-cron`.
- Docker startup preloads `pg_cron` and `graph`.
- Docker init SQL creates `pg_cron`, creates `graph`, and schedules
  `graph.run_scheduled_maintenance()` every five minutes as
  `pggraph-maintenance`.
- Docker base images are pinned by explicit version tag and digest.
- Non-Docker deployments that want scheduled maintenance should install and
  configure `pg_cron` or run `graph.run_scheduled_maintenance()` from their own
  scheduler.

Recreate Docker volumes to pick up new init SQL or pg_cron schedules. PostgreSQL
only runs files under `/docker-entrypoint-initdb.d/` when it initializes a fresh
data directory.

### Supply Chain Policy

Release dependencies are pinned and reviewed before they move:

- Rust direct dependencies use exact Cargo requirements plus committed lockfiles.
- Python sandbox dependencies use exact `==` pins.
- Docker base images use explicit version tags plus digests.
- Nix flake GitHub inputs are pinned in `flake.lock` and reviewed manually.
- New dependency versions should not be adopted into a release until they are at
  least 6 hours old and any package-manager fetch or install goes through
  `sfw`, unless a security fix requires an explicit exception.

Check dependency freshness without applying updates:

```bash
python3 scripts/check_dependency_updates.py
```

Supported Cargo and Python manifests are only rewritten when a maintainer names
the dependency and confirms:

```bash
python3 scripts/check_dependency_updates.py --update cargo:serde --yes
python3 scripts/check_dependency_updates.py --update pypi:streamlit --yes
```

Docker and Nix flake input updates are report-only and require manual changelog,
digest, provenance, or locked revision review.

<Callout type="warning">
  The dependency checker reports update candidates and review items by design.
  Do not treat checker output as automatic approval to upgrade dependencies.
</Callout>

### Release Gates

The full `pg17` release gate passed for this hardening branch:

```bash
PG_VERSION_FEATURE=pg17 ./tests/heavy/run_release_gate.sh
```

Coverage includes fmt, clippy, docs, unit tests, pgrx SQL tests, cargo-deny,
fuzz check, package validation, fresh install smoke, metadata audit,
SQLSTATE/ACL boundary tests, backup/restore, lock regressions, concurrency,
synthetic release smoke, and pgbench sync stress.

The heavy release gate also includes playground query validation:

```bash
./tests/heavy/playground_release_gate.sh
```

The playground gate prepares the Docker-backed Panama dataset, imports the same
query catalog used by the UI, and validates every sidebar SQL example. Stable
examples compare row counts and result hashes; operational examples with
volatile job IDs or timings compare row counts.

Set `PGGRAPH_PLAYGROUND_YES=1` only when release automation is allowed to
approve the first Panama dataset download. Set `RUN_PLAYGROUND=0` on the full
release gate only for constrained environments that cannot prepare the
Docker-backed playground dataset.

### Documentation

- Updated API reference, querying, sync/maintenance, configuration,
  installation, troubleshooting, build/persistence, known-issues, and roadmap
  docs.
- Marked completed alpha hardening items reflected in public docs.
- Added scheduler and release-testing guidance.
- Added playground release-gate documentation.
- Added dependency pinning, age-gate, and update-checker documentation.
- Expanded Rustdoc for query freshness configuration and CSR edge-store builder
  APIs.

### Upgrade Notes

- Review any consumer code expecting `graph.weighted_shortest_path()` to return
  a JSON-only payload; the API now returns path step rows.
- Rebuild graph artifacts after upgrading when release validation changes the
  persistence or build path being exercised.
- Recreate Docker volumes to pick up new init SQL or pg_cron schedules.
- Treat dependency-checker `UPDATE` and `REVIEW` output as release review work,
  not as automatic permission to upgrade.

### Commit Coverage

This release note covers the alpha hardening branch commits reviewed over
`main`, including sync freshness, edge-store safety, persistence fallback,
Docker scheduling, playground examples, and the follow-up release-gate and
supply-chain documentation changes.

## v0.1.0: Initial Alpha

The initial alpha release introduced pgGraph as a PostgreSQL extension for
building and querying a derived graph index over existing relational tables.

<Callout type="info">
  `v0.1.0` was the version previously published from `main`. New deployments
  should use `v0.1.2`; this entry is retained so the release-notes page tracks
  historical releases instead of only the latest merge.
</Callout>

### Highlights

- Added schema registration APIs for existing PostgreSQL tables and edge
  relationships.
- Added graph build and status APIs for creating the derived graph index.
- Added traversal, search, shortest-path, weighted-shortest-path, component,
  filter, and aggregation query surfaces.
- Added persistence support for `.pggraph` artifacts.
- Added Docker and package installation flows for PostgreSQL-backed evaluation.
- Added public user and contributor documentation for installation,
  configuration, querying, persistence, and release testing.

### Upgrade Notes

- `v0.1.2` supersedes this release and includes the `v0.1.1` breaking SQL
  contract changes. Review the `v0.1.1` breaking changes before moving
  applications from `v0.1.0`.
