# v0.54.0 — DVM Engine Hardening

> **Full details:** [v0.54.0.md-full.md](v0.54.0.md-full.md)

## What's New

v0.54.0 hardens the DVM (Differential View Maintenance) engine across seven
dimensions: recursion depth-limit enforcement, CTE-count cap, snapshot
fingerprint caching, expression visitor pattern, view-inlining relkind cache,
upstream frontier validation, and O(V+E) diamond detection.  Every change is
targeted at correctness and performance; no user-visible API surface changes.

### C-7: diff_node() Recursion Depth Guard

`diff_node()` now enforces a hard recursion depth limit drawn from
`pg_trickle.max_parse_depth` (default 64).  Exceeding the limit raises
`DiffDepthExceeded` with a clear user-actionable hint instead of overflowing
the call stack on pathological query nesting.

### R-7: DiffContext CTE Count Cap (OOM Guard)

Each differentiation pass now tracks the number of CTEs emitted.  When the
count reaches `pg_trickle.max_diff_ctes` (default 1000, range 10–100 000),
the engine returns `DiffCteCountExceeded` before allocating further memory,
preventing pathological queries from exhausting server memory.

### P-4: Snapshot Fingerprint Two-Level Cache

Snapshot CTE registration now uses a two-level cache: O(1) pointer identity
followed by structural fingerprint equality.  Identical subtrees share a
single CTE, eliminating redundant snapshot SQL generation for diamond-shaped
query plans.

### P-5: Expr::to_sql() Visitor Pattern

`Expr::to_sql()` delegates to a new `to_sql_into(&self, buf: &mut String)`
method that writes SQL directly into a pre-allocated buffer, eliminating
intermediate heap allocations for nested expressions.

### P-6: View-Inlining Relkind Cache

The view-inlining rewrite pass now caches relkind lookups for the duration of
each iteration, preventing repeated SPI catalog queries for the same relation.

### C-4: Upstream Stream-Table Frontier Validation

`generate_delta_query()` now validates that every upstream stream-table source
has a corresponding entry in the refresh frontier.  Missing entries return a
`StSourceFrontierMissing` error with the affected `pgt_id`, allowing the
scheduler to reinitialize rather than producing incorrect delta results.

### S-1: O(V+E) Diamond Detection

`detect_diamonds()` now calls the new `compute_all_ancestors()` helper which
traverses the DAG once in forward topological order, building all ancestor sets
in O(V+E) total work.  Per-branch ancestor lookup is then O(1) via the
precomputed map, replacing the previous O(V²) approach.
