> **Plain-language companion:** [v0.75.0.md](v0.75.0.md)

## v0.75.0 — API Polish, Documentation Excellence & Developer Experience

**Status: Released.** Derived from [ROADMAP.md](../ROADMAP.md).

> **Release Theme**
> Polish the SQL API surface and documentation to meet the world-class standard
> required before v1.0. This release normalises the API catalog, adds missing
> SQL reference sections, introduces type-safety wrappers for cross-domain
> identifiers, repairs doc corruption, and delivers the comparison matrix that
> operators need when evaluating pg_trickle against alternative IVM systems.

---

### Implementation Status

| Item | Title | Status |
|------|-------|--------|
| API-002 | `pgtrickle.metrics_summary` full SQL reference section | ✅ Done |
| API-003 | SQL function parameter naming convention documented | ✅ Done |
| API-004 | Generated API catalog return types converted to SQL-facing forms | ✅ Done |
| API-005 | Schedule-mode comparison table added to SQL reference | ✅ Done |
| CODE-003 | Typed `PgtId` / `StreamTableOid` wrappers in Rust | ✅ Done |
| DOC-001 | `plans/PLAN.md` architecture-doc table repaired + fragment-corruption lint | ✅ Done |
| DOC-002 | README GUC count updated to generated phrase | ✅ Done |
| DOC-003 | `metrics_summary()` section added to detailed SQL reference (same as API-002) | ✅ Done |
| DOC-004 | Stale-version scanner added to docs lint | ✅ Done |
| ARCH-004 | `docs/COMPARISONS.md` comprehensive IVM comparison matrix | ✅ Done |

---

### Detailed Item Descriptions

#### API-002 / DOC-003 — `metrics_summary()` Full SQL Reference Section

**Source:** PLAN_OVERALL_ASSESSMENT_14.md §API-002, §DOC-003  
**Severity:** Medium  
**Location:** `src/api/metrics_ext.rs`, `docs/SQL_REFERENCE.md`, `docs/SQL_API_CATALOG.md`

`metrics_summary()` appears in the generated API catalog but has no detailed
section in `docs/SQL_REFERENCE.md`, unlike `cache_stats()` and
`history_prune_status()`. Add a full section with:

- Function signature and SETOF column list
- Per-column descriptions with operational notes
- Grafana usage guidance (typical Grafana/Prometheus query pattern)
- Cost caveats (aggregates from `pgt_refresh_summary` — O(N stream tables)
  per call; do not call on every scrape for large installations)
- Example output row

**Exit criterion:** `grep -c "metrics_summary" docs/SQL_REFERENCE.md` ≥ 2
(TOC link + section heading).

---

#### API-003 — SQL Function Parameter Naming Convention

**Source:** PLAN_OVERALL_ASSESSMENT_14.md §API-003  
**Severity:** Medium  
**Location:** `src/api/create.rs`, `src/api/outbox.rs`, `src/api/spec.rs`,
  `docs/SQL_REFERENCE.md`

Core functions use bare names (`name`, `query`), while newer APIs use `p_name`,
`p_retention_hours`, or overload-specific names. This is visible in named-
argument SQL calls and generated docs.

Document the convention as a note in `docs/SQL_REFERENCE.md` (or a dedicated
SQL API conventions section): prefer bare user-facing argument names (`name`,
`query`, `schedule`); keep `p_` prefix only for internal wrappers or where
migration compatibility requires it.

**Exit criterion:** Convention documented in `docs/SQL_REFERENCE.md`.

---

#### API-004 — Generated API Catalog: SQL-Facing Return Types

**Source:** PLAN_OVERALL_ASSESSMENT_14.md §API-004  
**Severity:** Medium  
**Location:** `scripts/gen_catalogs.py`, `docs/SQL_API_CATALOG.md`

The catalog quality gate passes, but many rows show Rust return types:
`Result<(), PgTrickleError>`, `pgrx::JsonB (nullable)`, `String`,
`&'static str`, `bool`, etc. Convert these to SQL-facing forms in
`_normalize_return_type()`:

| Rust | SQL |
|------|-----|
| `Result<(), PgTrickleError>` | `void` |
| `Result<String, PgTrickleError>` | `text` |
| `Result<i64, PgTrickleError>` | `bigint` |
| `pgrx::JsonB` | `jsonb` |
| `String` | `text` |
| `&'static str` | `text` |
| `bool` | `boolean` |
| `i32` | `integer` |
| `i64` | `bigint` |
| `f64` | `double precision` |

Keep Rust return metadata in a developer-only footnote if needed.

**Exit criterion:** `grep "Result<\|pgrx::\|&'static" docs/SQL_API_CATALOG.md`
returns zero matches after regeneration.

---

#### API-005 — Schedule-Mode Comparison Table

**Source:** PLAN_OVERALL_ASSESSMENT_14.md §API-005  
**Severity:** Low  
**Location:** `docs/SQL_REFERENCE.md`

Add a compact comparison table for Duration / Cron / CALCULATED / IMMEDIATE
with use-case, example, and refresh-trigger semantics. Place it immediately
after the cron expression format table and before the first example.

**Exit criterion:** Table present in `docs/SQL_REFERENCE.md` schedule section.

---

#### CODE-003 — Typed `PgtId` / `StreamTableOid` Wrappers

**Source:** PLAN_OVERALL_ASSESSMENT_14.md §CODE-003  
**Severity:** Low  
**Location:** `src/api/outbox.rs`, `src/catalog.rs`

Casting `pgt_id: i64` into `pgt_relid: pg_sys::Oid` blurs two unrelated
identifier domains. Introduce:

- `PgtId(i64)` — internal sequence ID for a stream table row  
- `StreamTableOid(pg_sys::Oid)` — PostgreSQL relation OID visible in `pg_class`

These newtype wrappers make cross-domain casts hard to write accidentally.
Add `From` / `Into` impls for the underlying types and update the outbox
helper functions to use them.

**Exit criterion:** `grep "pgt_id as Oid\|pgt_id.*into.*Oid" src/` returns
zero matches.

---

#### DOC-001 — Repair `plans/PLAN.md` Architecture-Doc Table

**Source:** PLAN_OVERALL_ASSESSMENT_14.md §DOC-001  
**Severity:** Medium  
**Location:** `plans/PLAN.md`

The Key Architecture Docs table contains duplicated fragments and corrupted
text (`COST_MODEL` repeated, `LIMITATIONS` truncated with random chars). Fix
the table by restoring the intended rows. Add a fragment-corruption lint to
`scripts/check_docs_truth.py` (or a new `scripts/check_plan_index.py`) that
fails if any Markdown link in `plans/PLAN.md` contains non-word characters
inside the link text (indicating corruption).

**Exit criterion:** `plans/PLAN.md` table renders correctly; lint passes in CI.

---

#### DOC-002 — README GUC Count: Generated Phrase

**Source:** PLAN_OVERALL_ASSESSMENT_14.md §DOC-002  
**Severity:** Medium  
**Location:** `README.md:558`

`README.md` says "All 115 configuration parameters" but the generated
GUC catalog now reports 132. Replace the hard-coded count with a phrase
that doesn't require manual updates: e.g., "All configuration parameters
with types and defaults".

**Exit criterion:** `grep "All [0-9]* configuration parameters" README.md`
returns zero matches.

---

#### DOC-004 — Stale-Version Scanner

**Source:** PLAN_OVERALL_ASSESSMENT_14.md §DOC-004, §DEVEX-003  
**Severity:** Low  
**Location:** `Dockerfile.hub`, `Dockerfile.ghcr`, `scripts/`

Dockerfile comment examples still show `0.11.0-pg18` and `0.13.0-pg18.3`.
Add a `scripts/check_stale_versions.sh` script that:

1. Reads the current Cargo.toml version.
2. Scans a list of files for version-like patterns that do NOT match the
   current version or a known placeholder (`<version>`, `@CARGO_VERSION@`,
   `latest`).
3. Reports stale occurrences and exits 1 if any are found.

Wire it into `just lint-ci`.

**Exit criterion:** Script present; `just lint-ci` runs it; Dockerfile
comments updated to use `<version>` placeholders.

---

#### ARCH-004 — `docs/COMPARISONS.md` Comprehensive IVM Comparison Matrix

**Source:** PLAN_OVERALL_ASSESSMENT_14.md §ARCH-004  
**Severity:** Low  
**Location:** `docs/COMPARISONS.md`

`docs/COMPARISONS.md` exists but lacks:
1. A section on **Feldera** (open-source DBSP-based streaming SQL engine)
2. A unified comparison matrix across SQL coverage, consistency model, CDC
   model, performance characteristics, and operational model for all five
   systems: pg_ivm, Materialize, Feldera, DuckDB/DuckLake, and pg_trickle

Add both. The matrix should cover at least these axes:

| Axis | Description |
|------|-------------|
| SQL coverage | SELECT features supported (joins, aggregates, recursion, etc.) |
| Consistency model | How fresh are results? At what isolation level? |
| CDC model | How are source changes detected? |
| Performance | Throughput / latency profile |
| Operational model | What do you deploy? Where does the data live? |

**Exit criterion:** `docs/COMPARISONS.md` contains a Feldera section and a
comprehensive cross-system matrix.

---

### Phase Order

1. DOC-001 (quick fix, unblocks docs-lint)
2. DOC-002 + DOC-004 (README + Dockerfile + scanner, low risk)
3. API-004 (gen_catalogs.py, regenerate catalog, verify CI)
4. API-002/DOC-003 (SQL reference section, no code change)
5. API-003 (convention note, no code change)
6. API-005 (SQL reference table, no code change)
7. ARCH-004 (expand COMPARISONS.md)
8. CODE-003 (Rust type wrappers — highest compile risk, do last)

---

### Exit Criteria Checklist

- [x] API-002/DOC-003: `metrics_summary` section present in `docs/SQL_REFERENCE.md`
- [x] API-003: Parameter naming convention documented
- [x] API-004: `docs/SQL_API_CATALOG.md` contains no bare Rust types after regen
- [x] API-005: Schedule-mode comparison table in SQL reference
- [x] CODE-003: `PgtId` / `StreamTableOid` newtypes in `src/catalog.rs`; outbox helpers use them
- [x] DOC-001: `plans/PLAN.md` table not corrupted; fragment-corruption lint passes
- [x] DOC-002: README GUC count is not a hard-coded number
- [x] DOC-004: Stale-version scanner in `scripts/`; Dockerfile comments use `<version>`
- [x] ARCH-004: `docs/COMPARISONS.md` has Feldera section and comprehensive matrix
- [x] `just fmt && just lint` passes with zero warnings
- [x] `just test-unit` passes
- [x] Version bumped to 0.75.0 in `Cargo.toml`, `META.json`, `pg_trickle.control`
- [x] `CHANGELOG.md` updated
- [x] `ROADMAP.md` v0.75.0 status → Released
- [x] `roadmap/v0.75.0.md` created
