# v0.58.0 — Security & Correctness Hardening > **Full details:** [v0.58.0.md-full.md](v0.58.0.md-full.md) ## What's New v0.58.0 is the first release of the Assessment-Driven Hardening Arc, driven by the findings in the v0.57.0 overall assessment ([plans/PLAN_OVERALL_ASSESSMENT_12.md](../plans/PLAN_OVERALL_ASSESSMENT_12.md)). It addresses all HIGH-severity security and correctness findings before any feature work resumes. ### SEC-1/2: Ownership Checks for Outbox and Publication APIs (S-1, S-2) `attach_outbox()`, `detach_outbox()`, `attach_embedding_outbox()`, `stream_table_to_publication()`, and `drop_stream_table_publication()` now call `check_stream_table_ownership()` immediately after resolving the stream table metadata — the same guard used by every other mutating API. Previously, any role with `EXECUTE` on the `pgtrickle` schema could attach a pg_tide outbox or create a logical-replication publication for a stream table owned by a different role. ### COR-1: Multi-Column NOT IN + NULL Row Handling (C-1) The v0.55.0 multi-column `IN` rewrite now correctly handles `NULL` elements in the row constructor and `NULL`-producing columns in the subquery's target list. When any left-side element is a `NULL` constant, or when the rewrite would produce an anti-join that cannot faithfully represent `NOT IN` semantics (SQL UNKNOWN propagation), the DVM parser falls back to the original subquery-based execution path and emits a diagnostic note. ### COR-2: Recursive-CTE Depth Guard in DIFFERENTIAL Mode (C-2) The `ivm_recursive_max_depth` GUC is now applied consistently to both DIFFERENTIAL (`ChangeBuffer`) and IMMEDIATE (`TransitionTable`) modes. Previously only IMMEDIATE mode enforced the depth limit; a pathological recursive CTE definition in DIFFERENTIAL mode could loop until WAL or temp-buffer limits were exceeded. ### COR-3: WAL Decoder TOCTOU Advisory Lock (C-3) `is_slot_suitable_for_wal_transition()` and `poll_wal_changes()` are now executed inside the same SPI transaction, holding a `pg_advisory_xact_lock` keyed on the slot OID. This eliminates the race window where a concurrent `pg_drop_replication_slot()` could invalidate the slot between the eligibility check and the first WAL consumption. ### COR-4: Compact-Buffer Lock Contention Is Now Observable (C-4) `compact_change_buffer()` no longer returns `Ok(0)` when it fails to acquire the advisory lock. It now returns `CompactionResult::Contended`, increments a new shared-memory counter `pg_trickle_cdc_compact_contended_total`, and logs at `debug!` level. The counter is exposed via the Prometheus `/metrics` endpoint so operators can detect persistent contention. ### SEC-3: DDL Hook Escalates on SPI Failure (S-3) `handle_alter_table()` in `src/hooks.rs` no longer silently returns when `find_view_downstream_pgt_ids()` fails with an SPI error. It now retries once and, on repeated failure, raises an `error!()` so the originating DDL statement itself fails with a clear message. This prevents a catalog-query outage from leaving downstream stream tables invisibly stale. ### SEC-4: Schema Identifier Quoted in CDC Buffer Names (S-4) `buffer_qualified_name_for_oid()` now uses `sql_builder::qualified()` instead of `format!("{change_schema}.{base}")`, ensuring the schema identifier is properly quoted and safe against unusual schema names.