# Release Notes
Release notes are ordered newest first.
## 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 := ...)`, `graph.all()`, and `graph.any()`.
### 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. Consolidated P3 internals to a single remaining pgrx test layout
item.
- 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.
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.
### 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`.
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/`.
### 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.
The dependency checker reports update candidates and review items by design.
Do not treat checker output as automatic approval to upgrade dependencies.
### 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.
`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.
### 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`.