# 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.

<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`.
